1. 程式人生 > >C語言可變引數簡析

C語言可變引數簡析

今天在看程式碼的時候,看到了這樣一段除錯的程式碼,搞不清楚(...)這個是什麼意思,看了下相關資料,簡單記錄下。

#ifdef DEBUG
#define DBG(...) fprintf(stderr, " DBG(%s, %s(), %d): ", __FILE__, __FUNCTION__, __LINE__); fprintf(stderr, __VA_ARGS__)
#else
#define DBG(...)
#endif

1、printf程式碼

1

2

printf(“hello,world!”);其引數個數為1個。

printf

(“a=%d,b=%s,c=%c”,a,b,c);其引數個數為4個。

如何編寫可變引數函式呢?我們首先來看看printf函式原型是如何定義的。
在linux下,輸入man 3 printf,可以看到prinf函式原型如下:

1

2

3

SYNOPSIS

#include <stdio.h>

int printf(const char *format, ...);

後面的三個點...表示printf引數個數是不定的.
如何實現可變引數函式?
2. 編寫可變函式準備
為了編寫可變引數函式,我們通常需要用到<stdarg.h>標頭檔案下定義的以下函式:

1

2

3

4

void va_start(va_list ap, last);

type va_arg(va_list ap, type);

void va_end(va_list ap);

void va_copy(va_list dest, va_list src);

其中:
va_list是用於存放參數列表的資料結構。

va_start函式根據初始化last來初始化引數列表。

va_arg函式用於從引數列表中取出一個引數,引數型別由type指定。

va_copy函式用於複製引數列表。

va_end函式執行清理引數列表的工作。

上述函式通常用巨集來實現,例如標準ANSI形式下,這些巨集的定義是:

1

2

3

4

5

typedef char * va_list; //字串指標

#define _INTSIZEOF(n) ( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) )

#define va_start(ap,v) ( ap = (va_list)&v + _INTSIZEOF(v) )

#define va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )

#define va_end(ap) = (va_list)0 )

 使用巨集_INTSIZEOF是為了按照整數字節對齊指標,因為c呼叫協議下面,引數入棧都是整數字節(指標或者值)。

4、用va_list實現vprintf()示例

#include <stdio.h>
#include <stdarg.h>

void my_printf(const char *format, ...)
{
    int n;
    va_list arg_list;
    va_start(arg_list, arg_list);
    n = vprintf(format, arg_list);
    va_end(arg_list);
}

int main(int argc, char *argv[])
{
    int ai = 0;

    my_printf("%d\n", ai);

    return 0;
}

 

5、C語言可變引數函式簡單例項

引數列表的格式是強制性引數在前,後面跟著一個逗號和省略號(...),這個省略號代表可選引數。
可變引數函式要獲取可選引數時,必須通過一個型別為 va_list 的物件,它包含了引數資訊。這種型別的物件也稱為引數指標(argument pointer),它包含了棧中至少一個引數的位置。可以使用這個引數指標從一個可選引數移動到下一個可選引數,由此,函式就可以獲取所有的可選引數。va_list 型別被定義在標頭檔案 stdarg.h 中。

一個簡單的例子,說明可變引數的用法

#include <stdio.h>
#include <stdarg.h>

int simple(int num,...)        //num代表了要傳遞的可變引數的總數
{
        int i, result=0;
        va_list vl;     //va_list指標,用於va_start取可變引數,為char*
        va_start(vl,num);       //取得可變引數列表中的第一個值
        printf("num:%d, vl:%d\n",num,*vl);

        //訪問所有賦給valist的值
        for (i = 0; i < (num-1); i++)//這裡num表示可變引數列表中有多少個引數  
        {
              //這裡把vl往後跳過4個位元組(sizeof(int)大小)指向下一個引數,返回的是當前引數(而非下一個引數)
            result = va_arg(vl, int);  

            //這裡列印下,可以看出,vl總是指向result後面的那個引數  
            printf("in for  result:%d,  *vl:%d\n", result, *vl);
        }
        va_end(vl);//結束標誌  

        return result;
}

int main(int argc, char **argv)
{
        simple(5,1,2,3,4,5);

        return 0;
}

執行結果如下:

 

原文地址:http://www.runoob.com/cprogramming/c-variable-arguments.html

http://www.cnblogs.com/ThatsMyTiger/p/6924462.html

 https://www.cnblogs.com/edver/p/8419807.html