欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

C語言中變參函數(shù)傳參的實現(xiàn)示例

 更新時間:2021年08月12日 10:20:08   作者:lularible  
本文主要介紹了C語言中變參函數(shù)傳參,文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下

背景引入

近期在看一本書,叫做《嵌入式C語言自我修養(yǎng)》,寫的內(nèi)容對我?guī)椭艽螅且槐竞脮?。在?章,GNU C編譯器擴展語法精講一節(jié),這本書給出了一些變參函數(shù)的例子:

//1.變參函數(shù)初體驗
#include<stdio.h>
void print_num(int count,...)
{
	int *args;
	args = &count + 1;
	for(int i = 0;i < count;i++)
	{
		printf("*args:%d\n",*args);
		args++;
	}
}

int main(void)
{
	print_num(5,1,2,3,4,5);
	return 0;
}

上面的代碼很好理解:定義一個變參函數(shù)print_num,在函數(shù)內(nèi)部先取得第一個參數(shù)的地址賦值給一指針,然后將指針后移,取得后面的參數(shù)并打印出來。在main函數(shù)中,傳給print_num 6個參數(shù),按這個邏輯,應(yīng)該是打印出:

*args:1
*args:2
*args:3
*args:4
*args:5

但是結(jié)果卻出人意料:

打印出的值和傳進去的值完全不相等,甚至毫無規(guī)律可言。

問題分析

上述代碼中,是通過取首個參數(shù)的地址,并往后移動這個指針來獲得后面參數(shù)的,那么問題很可能出在兩個地方:

  • 指針移動的方式不正確
  • 參數(shù)的地址排布可能不是連續(xù)的

我們一個一個來看,先暫且假定這些參數(shù)地址是連續(xù)的,且相隔一樣的距離。那么我們就可以聚焦于指針的移動方式了。指針移動是“args++”這一行語句來控制的。筆者修改了一下書上的代碼:

#include<stdio.h>
void print_num(int count,...)
{
	int *args;
	args = &count;
	for(int i = 0;i <= count;i++)
	{
		printf("addr:%p\n",args);
		printf("*args:%d\n",*args);
		args++;
	}
}

int main(void)
{
	print_num(5,1,2,3,4,5);
	return 0;
}

主要增加了對于每個參數(shù)的地址的打印,運行結(jié)果如下:

筆者發(fā)現(xiàn)這個"args++"每次往后移動4個字節(jié),這是因為對于"int"型指針的移動操作,是以4(sizeof(int))為基本單位的。同理,對于"char"型指針的移動操作,以1(sizeof(char))為單位。

指針大小

一個"int"型指針大小如果等于4,那么上述對于指針移動操作就沒問題??墒?int"型指針大小真的等于4嗎?

筆者用代碼來測試下:

#include<stdio.h>

int main()
{
	char*	charPoint;
	int*	intPoint;
	double*	doublePoint;

	struct st{
		int first;
	};

	struct st *structPoint;

	printf("sizeof(char*):%ld\n",sizeof(charPoint));
	printf("sizeof(int*):%ld\n",sizeof(intPoint));
	printf("sizeof(double*):%ld\n",sizeof(doublePoint);
	printf("sizeof(struct*):%ld\n",sizeof(structPoint));
	return 0;
}

運行結(jié)果:

可以看到,不僅"int"型指針是8字節(jié)大小,"char"、"double"和結(jié)構(gòu)體指針也都是8字節(jié)大小。這是因為筆者電腦安裝的是64位系統(tǒng)。所以書上代碼的"int"型指針自增操作不適用于筆者,筆者將其改為“args += 2”,在dev c++這個IDE中可以得到正確的結(jié)果,但在ubuntu gcc下還是不對。

參數(shù)位置排布

解決了第一個指針移動步長問題,還是得不到正確答案。筆者懷疑參數(shù)地址很可能不連續(xù)。如何看函數(shù)的參數(shù)地址信息?方法有很多,筆者就選一種比較快捷的方式——看匯編代碼。

在ubuntu的終端框輸入

gcc -S [源文件]

就能得到一個帶".s"后綴的匯編代碼文件。

我們對比著看main函數(shù)與print_num函數(shù)中關(guān)于參數(shù)傳遞的部分:

在main函數(shù)中,各個參數(shù)被放入不同的寄存器,在print_num函數(shù)中,又從寄存器中將參數(shù)取出來放入print_num的函數(shù)堆棧中。仔細看各個參數(shù)最終被放入的堆棧位置,發(fā)現(xiàn)第一個參數(shù)地址和第二個參數(shù)地址差了28個字節(jié),而后面的參數(shù)地址之間都是差8個字節(jié)。這也就解釋了為何之前的代碼結(jié)果不對了。

解決問題

所以只要在第一個參數(shù)地址的基礎(chǔ)上加上偏移量28即可("char*"型)。

運行結(jié)果符合預(yù)期:

但是為什么第一個參數(shù)和第二個參數(shù)間隔28字節(jié),筆者暫時還不清楚,盲猜需要去看gcc中編譯器的相關(guān)知識。

額外的測試

以往對于固定參數(shù)個數(shù)的普通函數(shù)的傳參,是這樣處理的:前幾個參數(shù)放入寄存器,若個數(shù)超出,則壓入函數(shù)堆棧。筆者有點好奇變參函數(shù)是否也如此,就給這個print_num傳了18個參數(shù):

匯編代碼如下:

這說明了變參函數(shù)的傳參規(guī)則和普通函數(shù)并無兩樣。

總結(jié)

在看書的時候,我喜歡邊看邊敲代碼,這一次照著書上敲的代碼運行結(jié)果不對,就有了上面的一些探究過程。如果我沒有動手實踐,以后碰到類似問題時很可能會蒙圈。所以動手實踐很有必要。

另外,書上的東西并不一定全對,并且它的正確性需要有特定的前提做保證。比如,要是我使用的是32位系統(tǒng),且編譯器在處理變參函數(shù)時將參數(shù)連續(xù)壓棧,那么書上的代碼就是完全正確的。我們無需害怕這些坑,我們需要做的就是去找到這些前提條件,去找到問題的本質(zhì)點,最后解決問題。

參考資料

《嵌入式C語言自我修養(yǎng)——從芯片、編譯器到操作系統(tǒng)》

到此這篇關(guān)于C語言中變參函數(shù)傳參的實現(xiàn)示例的文章就介紹到這了,更多相關(guān)C語言變參函數(shù)傳參內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 關(guān)于C++的.cpp文件運行全過程

    關(guān)于C++的.cpp文件運行全過程

    這篇文章主要介紹了C++的.cpp文件運行全過程,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-02-02
  • C/C++實現(xiàn)貪吃蛇逐步運動效果

    C/C++實現(xiàn)貪吃蛇逐步運動效果

    這篇文章主要為大家詳細介紹了C/C++實現(xiàn)貪吃蛇逐步運動效果的相關(guān)資料,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2016-05-05
  • 一問了解C++ 的移動語義

    一問了解C++ 的移動語義

    本文主要介紹C++ 的移動語義,移動語義并不是一個容易理解的概念,很多程序員可能對其存在一定的疑惑,今天我們就來探討一下 C++ 中的移動語義
    2023-04-04
  • C語言調(diào)用攝像頭實現(xiàn)生成yuv未壓縮圖片

    C語言調(diào)用攝像頭實現(xiàn)生成yuv未壓縮圖片

    這篇文章主要為大家詳細介紹了C語言如何調(diào)用攝像頭實現(xiàn)生成yuv未壓縮圖片,文中的示例代碼講解詳細,具有一定的學(xué)習(xí)價值,感興趣的小伙伴可以參考一下
    2023-11-11
  • C語言關(guān)鍵字const和指針的結(jié)合使用

    C語言關(guān)鍵字const和指針的結(jié)合使用

    這篇文章主要介紹了C語言關(guān)鍵字const和指針的結(jié)合,本文給大家介紹的非常詳細,具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-02-02
  • C語言 詳細講解#pragma的使用方法

    C語言 詳細講解#pragma的使用方法

    #pragma 指令對每個編譯器給出了一個方法,在保持與C和C++語言完全兼容的情況下,給出主機或操作系統(tǒng)專有的特征。依據(jù)定義,編譯指示是機器或操作系統(tǒng)專有的, 且對于每個編譯器都是不同的
    2022-04-04
  • c++中的string常用函數(shù)用法總結(jié)

    c++中的string常用函數(shù)用法總結(jié)

    以下是對c++中的string常用函數(shù)的用法進行了詳細的分析介紹,需要的朋友可以過來參考下
    2013-09-09
  • 深入解析C++ STL中的常用容器

    深入解析C++ STL中的常用容器

    這里我們不涉及容器的基本操作之類,只是要討論一下各個容器其各自的特點。STL中的常用容器包括:順序性容器(vector、deque、list)、關(guān)聯(lián)容器(map、set)、容器適配器(queue、stac)
    2013-09-09
  • Linux下Select多路復(fù)用實現(xiàn)簡易聊天室示例

    Linux下Select多路復(fù)用實現(xiàn)簡易聊天室示例

    大家好,本篇文章主要講的是Linux下Select多路復(fù)用實現(xiàn)簡易聊天室示例,感興趣的同學(xué)趕快來看一看吧,對你有幫助的話記得收藏一下,方便下次瀏覽
    2021-12-12
  • C++實現(xiàn)簡單推箱子小游戲

    C++實現(xiàn)簡單推箱子小游戲

    這篇文章主要為大家詳細介紹了C++實現(xiàn)簡單推箱子小游戲,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2020-08-08

最新評論