C語言不定參數


最近,遇到一個c語言的不定參數問題。其實,對於c語言的不定參數問題,只需要三個函數就可以搞定了。這三個函數的頭文件是<stdarg.h>,其實下面的三個函數都是一個宏定義(macro)。
    這三個函數是:
    void va_start(va_list ap, last);
    type va_arg(va_list ap, type);
    void va_end(va_list ap);
    如果需要進行其他的一些操作,可以查看一下man手冊進行查詢。
    在這三個函數解釋之前,先看一個變量va_list,這個變量的類型是什么呢?通過查看內核源代碼,一直追蹤下去,才發現它的類型是void *類型的。
    對於va_start(va_list ap, last)函數,這個函數是用來初始化指針變量ap(va_list類型)的,以后處理參數就是默認從ap處開始處理。last一般為char *傳過來參數列表的第一個參數。
    對於va_arg(va_list ap, type)函數來說,就是將ap指針按照type類型向后移動,然后取出ap指針所指的那個參數。
    對於va_end(va_list ap)一般和va_start(va_list ap, last)配套使用,做一些善后處理的事情。
    這里有一個問題,當我們取參數的時候,如何判斷我們要取的參數已經取完了?開始我是這么想的,通過va_arg的返回值進行判斷,通過查閱資料,都是這么說的,看來我的猜想是對的。當我把程序寫出來進行測試的時候,發現不是這樣的:
#include <stdio.h>
#include <stdarg.h>
int sum(const int , ...);
int main(void)
{
    printf("The result is:%d/n", sum(10, 9, 8));
    return 0;
}
int sum(const int first, ...)
{
    va_list argp;
    int sum = 0;
    int tmp;
    va_start(argp, first);
    sum += first;
    printf("%d/n", first);
    while((tmp = va_arg(argp, int)) != 0) {
        printf("%d/n", tmp);
        sum += tmp;
    }
    va_end(argp);
    return sum;
}
這個程序的運行結果是:
10
9
8
6676468
134513824
The result is:141190319
    這個結果說明,通過va_arg的返回值進行參數是否取完來判斷是有問題的。
    會不會是通過argp的值來判斷的呢?讓我們來做個測試:
#include <stdio.h>
#include <stdarg.h>
int sum(const int , ...);
int main(void)
{
    printf("The result is:%d/n", sum(10, 9, 8));
    return 0;
}
int sum(const int first, ...)
{
    va_list argp;
    int sum = 0;
    int tmp;
    va_start(argp, first);
    sum += first;
    printf("%d/n", first);
    while(argp) {
        tmp = va_arg(argp, int);
        printf("%d/n", tmp);
        sum += tmp;
    }
    va_end(argp);
    return sum;
}
    這個程序的執行結果出乎我的意料,出現了段錯誤。
    至於如何修改這個程序把不定參數取出來,我還是沒有找到解決方法。后來,我想到了printf()函數,我查看了它的源代碼,其中主要是調用了vsprintf()函數,至於為什么調用vsprintf()函數,我想可能是為了實現類似於fprintf()之類的函數調用的方便,這樣也提高了函數的利用率。printf()函數的主要代碼:
328 va_start(args, fmt);
329 n = vsprintf(sprint_buf, fmt, args);
330 va_end(args);
    我繼續查看了vsprintf()函數,結果發現,在這個函數當中,它好像是通過判斷字符串當中“%”號的多少來決定后面參數的個數的。想到這里,我斷定,在想調用不定參數這樣的函數的時候,其實是需要指出參數的個數的,只是是通過間接的方式。比如我們最熟悉的printf()函數,其實我們在第一個參數當中,通過%號已經指出了參數的個數,不是嗎?
    想到這里,我想到了之前看到man手冊中給出的例子為什么是這樣的:
#include <stdio.h>
       #include <stdarg.h>
       void
       foo(char *fmt, ...)
       {
           va_list ap;
           int d;
           char c, *s;
           va_start(ap, fmt);
           while (*fmt)
               switch (*fmt++) {
               case 's': /* string */
                   s = va_arg(ap, char *);
                   printf("string %s/n", s);
                   break;
               case 'd': /* int */
                   d = va_arg(ap, int);
                   printf("int %d/n", d);
                   break;
               case 'c': /* char */
                   /* need a cast here since va_arg only
                      takes fully promoted types */
                   c = (char) va_arg(ap, int);
                   printf("char %c/n", c);
                   break;
               }
           va_end(ap);
       }
    這里的話,不是就通過第一個參數指定之后才讀取的嗎?其實我覺得是間接的告訴了參數的個數。
    通過上面的分析,下面做了一個簡單的不定參數的應用。
    問題描述:給定一些字符串,求出它們的最長開始字串。
    實驗代碼如下:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
void fun(char *fmt, ...);
int main()
{
    fun("sss", "fanabcd", "fanfanfanfan", "fanyyyyyyyyyyyy");//sss 表示了不定參數的個數
    return 0;    
}
void fun(char *fmt, ...)
{
    va_list argp;
    char * str, res[20] = {0};
    int i;
    va_start(argp, fmt);
    if(*fmt == 's') {
        str = va_arg(argp, char *);
        strcpy(res, str);
    }
    fmt++;
    while(*fmt) {
        if(*fmt++ == 's') {
            str = va_arg(argp, char *);
            i = 0;
            while(res[i] != '/0') {
                if(res[i] != str[i]) {
                    res[i] = 0;
                    break;
                }
                i++;
            }
        }
    }
    va_end(argp);
    printf("The result is:%s/n", res);
}
    程序的執行結果是:
The result is:fan
    通過這樣的折騰,就把c語言的不定參數簡單地應用起來了


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM