2016-11-19 99 views
-1

這段代碼有什麼問題?EXC_BAD_ACCESS當調用vprintf()

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

void myprintf(const char * format, ...) __printflike(1, 2); 

int main(int argc, const char * argv[]) { 
    printf("%s\n"); 
    myprintf("%s\n"); 
    return 0; 
} 

void myprintf(const char * format, ...) { 
    if (format) { 
     va_list arguments; 
     va_start(arguments, format); 
     vprintf(format, arguments); 
     va_end(arguments); 
    } 
} 

通過使用__printflike我得到一個不錯的警告,就像printf。但不同於printf,其中至少打印垃圾,我得到EXC_BAD_ACCESS在調用vprintf如下所示:

enter image description here

有沒有什麼辦法可以使這項工作? 謝謝!

更新:我的理解是通過調用數錯誤的參數的函數得到了一個未定義的行爲,但我想myprintf表現就像printf做(沒有崩潰)。那可能嗎?在撥打vprintf以避免異常之前,有什麼方法可以檢查參數嗎?

UPDATE 2:我想我現在明白了,感謝所有的評論和回答。對於這個非常簡單的例子,我認爲是更好地使用宏,這向主叫點未能快速和崩潰:

enter image description here

+0

「printf,它至少打印垃圾」。這不是保證的行爲。當您故意將代碼中的錯誤添加到具有未定義行爲的代碼中時,您無法期望它「至少打印垃圾」。 UB意味着行爲是不可預測的。它可以立即崩潰,它可以後來崩潰,它可以打印垃圾,它可以打印什麼,... – kaylum

+1

[是否「未定義行爲」真的允許*發生任何事情?](http://stackoverflow.com/questions/ 32132574/does-undefined-behavior-really-permit-anything-to-happen) – kaylum

+0

@kaylum我更新了我的問題,因爲我想知道是否有一種方法可以讓我的函數的行爲像'printf',在它的未定義的方式。從你的角度來看...如果調用者傳遞錯誤的參數就足夠了,那麼記錄該行爲是不確定的?謝謝! – cromandini

回答

1

Undefined意味着不可預知的。在一次運行中printf可能會產生垃圾,而在另一次運行中則可能產生EXC_BAD_ACCESS。您無法複製undefined behavior。在這種情況下,格式字符串中的%s字詞表示printf需要查找C字符串。根據你的libc實現,當你沒有指定第二個參數時,它可能會在某處找到它。如果碰巧在這個指針不遠處發現空字符,你會得到垃圾輸出。如果不是,printf將繼續搜索字符串的末尾,直到它超出分配給程序的內存範圍,您將獲得EXC_BAD_ACCESS

0

這是不可能的 - 至少不是以便攜的方式 - 來確定傳遞給函數的參數數量。格式說明符是printf確定從堆棧中彈出多少個值的唯一方式,因此輸入錯誤的格式說明符會導致未定義的行爲。這只是你需要學習然後繼續前進的C語言中的一個。

通過試圖「糾正」這樣的事情,你可能會讓代碼更難讀,難以讓其他人理解。

0

有沒有什麼辦法可以在調用vprintf之前檢查參數以避免異常?

只是一個:認真編譯器的警告,並消除警告指出你的編程錯誤。

請參閱:現在變得越來越冬季,街道上會有泥土和積雪(至少在歐洲),所以您有自己喜歡的車庫將冬季輪胎安裝到保時捷上。在這個漂亮的車,你發現在儀表板下面貼的回報(放在那裏由車庫):

enter image description here

(APX100英里/小時)

該標籤提醒您,那新裝冬季輪胎不是支持汽車的最高速度。

現在,當輪胎即將破裂時,您不會開得更快,因爲車胎會停下來,不是嗎?

這取決於你,司機尊重這個警告!

;-)

相關問題