C 可變引數函式分析(va_start,va_end,va_list...)
#PS:要轉載請註明出處,本人版權所有
#PS:這個只是 《 我自己 》理解,如果和你的
#原則相沖突,請諒解,勿噴
系統:Linux 4.4.0-31-generic #50-Ubuntu SMP Wed Jul 13 00:07:12 UTC 2016 x86_64 x86_64 x86_64 GNU/Linux
在幾年前,由於興趣需要,去研究了c的不定引數問題,當時由於太懶,沒有記錄任何資料,導致現在實際需要的時候,又要重新來過。嗚呼哀哉,太煩了~~~~~~~~~~~~~~
首先,c不定引數所定義的巨集的標頭檔案在 stdarg.h中。在我的系統中在這裡:/usr/lib/gcc/x86_64-linux-gnu/5/include/stdarg.h,原始碼我就不貼了,就簡要分析幾個重要巨集的原理。
va_list //此巨集依賴與不同的平臺和作業系統。
//常用定義:(具體和編譯器有關,其實瞭解透後,都差不多)
typedef char * __builtin_va_list;//(注意可能是這樣定義的)
(or)
typedef void * __builtin_va_list;//(注意可能是這樣定義的)
typedef __builtin_va_list __gnuc_va_list;
typedef __gnuc_va_list va_list;
_INTSIZEOF(n) //此巨集是windows上定義的,目的是為了考慮相容一些記憶體地址對齊的系統,n應該佔多少位元組,如:arm指令集是4位元組對齊訪問,Thumb指令集是24位元組對齊訪問.在linux上,gcc編譯器會內部定義一個類似的巨集,來代表對齊的位元組數。其用法是為了根據一個確定的引數,來依次確定不定引數中的每一個引數。
#define _INTSIZEOF(n) \
( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) )
//一般在一個作業系統中,int型別所佔的位元組數即為當前對齊的位元組數,一般為4或者8。關於此巨集的詳細分析,以下的分析來至於網上,帶入sizeof(n) = 4,8即可明白:
#define _INTSIZEOF(n) ((sizeof(n) + x) & ~(x))
x = sizeof(int) - 1 = 3 = 0000 0000 0000 0011(b)
~x = 1111 1111 1111 1100(b)
va_start(v,l) //此巨集獲取的是可變引數中的第一個引數的地址
#define __builtin_va_start(v,l) \
( v = (va_list)&l + _INTSIZEOF(l) )//(注意可能是這樣定義的),l的地址加上l地址所佔的空間
#define va_start(v,l) __builtin_va_start(v,l)
va_arg(v,l)//此巨集是使下一個可變引數的地址賦值給v,同時返回開始時v地址所指向的值,注意:此時v已經指向下一個引數地址,但是表示式返回的值是初始v的值,《《這裡只需要搞清楚括號優先順序就能夠明白》》。
#define __builtin_va_arg(v,l) \
( *(l *)((v += _INTSIZEOF(l)) - _INTSIZEOF(l)) )//(注意可能是這樣定義的)
#define va_arg(v,l) __builtin_va_arg(v,l)
va_end(v)//此巨集處理va_list宣告的一個指標,防止出現野指標。有始有終。
#define __builtin_va_end(v)\
( v = (va_list)0 )
#define va_end(v) __builtin_va_end(v)
來個例子,(t.c)
#include <stdarg.h>
#include <stdio.h>
void ttt(char * fuk,...);
int main(int argc, char * argv[]){
ttt("fuk",2333,"this is 23333333333333333");
return 0;
}
void ttt(char * fuk,...){
va_list arg;
int a;
char *b;
va_start(arg,fuk);
a = va_arg(arg,int);
b = va_arg(arg,char *);
va_end(arg);
printf("%d,%s\n",a,b);
}
>>gcc t.c
>>./a.out
最後的注意:
1 變參函式必須有一個以上的指定引數
2 變參的《《型別》》必須通過一定方式已知(如格式化字串,”%d,%s”等等),否則就是定死的
3 變參的《《個數》》也必須通過一定方式已知(如格式化字串,”%d,%s”等等),否則就是定死的
4 c的函式引數入棧方式是從右到左,棧的地址一般是從高到底。
#PS:請尊重原創,不喜勿噴
#PS:要轉載請註明出處,本人版權所有.
有問題請留言,看到後我會第一時間回覆
相關文章
- C++ 函式的可變引數C++函式
- C可變引數函式 實現函式
- C語言使用函式引數傳遞中的省略號:va_list, va_start, va_arg, va_endC語言函式
- PHP函式,引數,可變參函式.PHP函式
- Swift 呼叫 Objective-C 的可變引數函式SwiftObject函式
- Go函式接收可變引數Go函式
- Python 函式(可變引數)Python函式
- 遞迴函式,可變引數列表遞迴函式
- PHP 函式可變數量的引數列表PHP函式變數
- php實現函式可變引數列表PHP函式
- golang學習之路之函式可變引數Golang函式
- va_start和va_end使用詳解
- c++可變模板引數C++
- va_list/va_start/va_arg/va_end深入分析
- 自己實現一個簡單可變引數函式函式
- C 可變長引數 VS C++11 可變長模板C++
- C++逆向 可變引數HookC++Hook
- C++11 可變引數模板C++
- C可變引數的實現
- python---函式引數、變數Python函式變數
- TypeScript 函式可選引數和預設引數TypeScript函式
- [ASM C/C++] C語言函式的可選性自變數ASMC++C語言函式變數
- python函式變長引數Python函式
- C語言可變引數詳解C語言
- 淺談C#可變引數paramsC#
- Day10 函式基礎+函式三種定義形式 + 函式的返回值、物件和引數 + 可變長引數函式物件
- php函式之如何用預設引數和可變長度引數方式傳遞?PHP函式
- [C]可變參量,debugprint函式函式
- C/C++—— 分析命令列引數的getopt()函式使用介紹C++命令列函式
- javascript函式引數和函式內同名變數的關係JavaScript函式變數
- 可變資料型別不能作為python函式的引數資料型別Python函式
- 【Java】可變引數Java
- Swift: 可變引數Swift
- Java可變引數Java
- Java 可變引數Java
- C++行內函數、函式過載與函式預設引數C++函數函式
- 對 “C語言指標變數作為函式引數” 的個人理解C語言指標變數函式
- 函式引數 引數定義函式型別函式型別