程序的主函數main的參數叫做命令行參數,他們是程序在運行時的輸入數據,其參數個數是可變的。
除了main函數之外的函數,其參數個數也可以是可變的,這就是變長參數表。
棧
在進程中,程序中棧的方向都是從高地址到低地址擴展的,即棧底在高處。C語言函數參數採用自右向左的入棧順序,一個原因就是爲了支持可變長參數形式。這樣使得右邊的參數先入棧,在高地址,從最左邊的參數開始只需做地址加法就能找到其他參數。
main主函數獲取命令行參數
下面是主函數從高地址到低地址的棧結構:
0xc0000000:棧底
0xbffffffc:NULL(0x00000000)
程序名稱字符串值 *
環境變量字符串值 *
命令行參數字符串值 *
ELF Auxiliary Vectors
NULL(結束envp[])
環境變量字符串地址列表(envp[])
NULL(結束argv[])
命令行參數字符串地址列表(argv[])
%esp:命令行參數個數(dword argc)
0xbffffffc:NULL(0x00000000)
程序名稱字符串值 *
環境變量字符串值 *
命令行參數字符串值 *
ELF Auxiliary Vectors
NULL(結束envp[])
環境變量字符串地址列表(envp[])
NULL(結束argv[])
命令行參數字符串地址列表(argv[])
%esp:命令行參數個數(dword argc)
int main(int argc, char** argv)
或者
int main(int argc, char* argv[])
1、標準的命令行參數獲取方法
argc是命令行參數個數,argv是指向各個參數的指針數組。
#include <stdio.h>
int main(int argc, char ** argv)
{
int i;
for (i=0; i < argc; i++)
printf("Argument %d is %s.\n", i, argv[i]);
return 0;
}
getopt() 函數位於 unistd.h 系統頭文件中。它使得可以以"-a -i"這樣的形式來設置不同類型的靈活的命令行參數。
普通函數的可變參數
1、標準提取方法
想要使用可變參數表,那麼要求參數表必須至少包括一個有名參數。下面的宏包含在stdarg.h中。
va_list類型:該類型的變量用於依次指向各個無名參數。
void va_start (va_list ap, paramN)宏函數。用於初始化va_list。
參數一:宏執行完之後,ap會指向第一個無名參數。
參數二:最有一個有名參數。
void va_copy (va_list dest, va_list src)宏函數。用於拷貝一份va_list。
type va_arg (va_list ap, type)宏函數,用於取出一個無名參數。
參數一:當前的va_list變量,每執行一次va_arg後,該變量就會後移一個參數。
參數二:指定該變量的數據類型,類型會決定va_list後移的步長。
void va_end (va_list ap)宏函數。用於做一些清理工作。
#include <stdarg.h>
#include <stdio.h>
// this function returns minimum of integer numbers passed. First
// argument is count of numbers.
int min(int arg_count, ...)
{
int i;
int min, a;
// va_list is a type to hold information about variable arguments
va_list ap;
// va_start must be called before accessing variable argument list
va_start(ap, arg_count);
// Now arguments can be accessed one by one using va_arg macro
// Initialize min as first argument in list
min = va_arg(ap, int);
// traverse rest of the arguments to find out minimum
for(i = 2; i <= arg_count; i++) {
if((a = va_arg(ap, int)) < min)
min = a;
}
//va_end should be executed before the function returns whenever
// va_start has been previously used in that function
va_end(ap);
return min;
}
int main()
{
int count = 5;
// Find minimum of 5 numbers: (12, 67, 6, 7, 100)
printf("Minimum value is %d", min(count, 12, 67, 6, 7, 100));
getchar();
return 0;
}
2、自主獲取可變參數
如果對可變參數的個數和棧足夠熟悉的話可以自主從棧中讀取無名參數。
下面是一個可變長參數的例子,實現多個數的相加。第一個參數是後面參數的個數。
int add(int num, …)
{
int sum = 0;
int *p =(int*)&num + 1;
for(int i=0;i<num;i++)
sum += *p++;
return sum;
}