2014-02-19 18 views
2

我最近重新開始使用C,我決定編寫一個庫作爲stdio.h的包裝。目標是儘可能地執行錯誤檢查,以便用戶在調用stdio函數時不必自行執行。這部分用於學習,部分用於實際使用(因爲我經常使用stdio)。使用可變參數在我的printf包裝中沒有返回錯誤

當我編寫以下內容(在main中)時,gcc在編譯時給出一個錯誤,因爲應該有一個整數作爲另一個參數,但沒有傳遞。

printf("Your integer: %d\n"); 

在情況下,它是非常有用的,這裏是我的編譯器標誌:

-std=c11 -pedantic-errors -Wall -Wextra -Werror 

這是我目前的包裝功能的一部分。它完美和不少錯誤檢查時,通過有效/正確的參數:

uintmax_t gsh_printf(const char *format, ...) 
{ 
    va_list arg; 
    int cnt; 
    va_start(arg, format); 
    cnt = vprintf(format, arg); 
    va_end(arg); 
    // Analyze cnt and check for stream errors here 
    return (uintmax_t)cnt; 
} 

但這裏的問題,如果我叫:

gsh_printf("Your integer: %d\n"); 

它確實給出一個錯誤,並且它甚至運行!通常的輸出是一樣的東西:

Your integer: 1799713 

或者其他一些數字,這意味着它的訪問沒有分配給它的內存,但它從來沒有給分段錯誤要麼。

那麼,它爲什麼不給出任何類型的錯誤?我該如何編寫自己的代碼,以便在檢查類型,參數數量等後發生編譯時錯誤或至少運行時錯誤?

當然,任何幫助非常感謝,如果您需要更多信息,請讓我知道。謝謝!

+0

看看那裏的printf定義頁眉,它必須有某種註解所以編譯器知道把它作爲格式字符串 – paulm

+0

我以前檢查過,但stdio.h中沒有提示,只是一個合理的正常函數聲明。我找不到一個stdio.c文件,所以我認爲它可能已經用另一種語言編寫或者預編譯或者其他東西。 – Leonhart231

+0

在不添加額外參數的情況下傳遞printf()一個「%d」(因爲printf()使用C的可變參數)在語法上是合法的。編譯器抱怨的原因是因爲它被編程。它盡最大努力注意到這可能是一個「永遠」無法預期的語義問題,因此會引發警告/錯誤。正在顯示的數據是「垃圾」。它不拋出分段錯誤的原因可能是因爲它將先前的堆棧值解釋爲缺少的int參數。除非您瀏覽頁面或其他操作系統錯誤,否則您可能不會看到錯誤。 – MrHappyAsthma

回答

4

With fprintf and fscanf函數族,如果缺少轉換規範相應的參數,函數調用會調用未定義的行爲。

隨着gcc使用格式(原型,字符串索引,第一 - 校驗)功能屬性來請求診斷:

extern uintmax_t gsh_printf(const char *format, ...) 
    __attribute__ ((format (printf, 1, 2))); 

uintmax_t gsh_printf(const char *format, ...) 
{ 
    va_list arg; 
    int cnt; 
    va_start(arg, format); 
    cnt = vprintf(format, arg); 
    va_end(arg); 
    // Analyze cnt and check for stream errors here 
    return (uintmax_t)cnt; 
} 

見文檔原型與字符串的說明指數第一對檢查

http://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html

例如上面的例子,用-Wall(因爲-Wformat),有這樣的說法:

gsh_printf("Your integer: %d\n"); 

你會得到這樣的警告:

警告:格式 '%d' 預期匹配「詮釋」參數[-Wformat]

隨着-Wall(因爲-Wformat-extra-args),你也將獲得額外的參數的警告:

gsh_printf("Your integer: %d\n", 0, 1); 

警告:對格式的參數太多[-Wformat-額外參數]

+0

我試了一下,它完美的作品!我希望它是標準的,但它是一個很好的,乾淨的解決方案。謝謝! – Leonhart231

+0

@ Leonhart231不客氣! – ouah

0

在C中,無法確定使用va_list時傳遞的參數數量是否是所需的參數數量。在C調用約定中,參數從最右邊的參數開始被推入堆棧。 printf的工作方式是分析格式字符串,並在需要時從堆棧中彈出一個值。因此,你叫

gsh_printf("Your integer: %d\n");

您需要提前很多爭論是如何提供不能使用的va_list做才能知道什麼時候獲得的隨機數。

您可以通過使用某種容器類來容納所有參數並使用容器中元素的數量來檢查是否有足夠的數量。

另請注意,'args'只是一個指向參數列表開始的指針。所以當你將它傳遞給vprintf時,vprintf只是打印指針的值。

+0

有趣的想法。我的部分目標是保持函數參數與向後兼容的標準函數相同,但值得考慮。 – Leonhart231

相關問題