回答
這就是爲什麼:
printf("%s\n", 42); // this will clobber the stream
這會導致緩衝區溢出 - 編譯器不能一般檢查在printf
第一個參數的格式字符串對應類型的後續參數。它可能在上述情況下做到這一點 - 因爲字符串是硬編碼的 - 有些編譯器可以。 但是通常格式字符串可以在運行時確定,因此編譯器無法檢查其正確性。
但這些檢查屬於特例,以printf
。如果您使用與printf
相同的簽名編寫您自己的myprintf
函數,將會有無法來檢查類型安全性,因爲簽名使用省略號...
,它省略函數中的所有類型信息。
GCC的'format'屬性可用於將相同的檢查應用於您自己的'myprintf'函數 –
您的示例不會導致緩衝區溢出!它只會打印字符串地址。 –
@LS_dev對,很好的觀察。我改變了它。 –
從C++ FAQ:
[15.1]我爲什麼要使用
<iostream>
代替傳統<cstdio>
?[...]
更多類型安全:隨着,對象被I/O的類型是由編譯器靜態地已知的。相反,使用「%」字段動態地找出類型。
[...]
爲printf
,編譯器不能檢查的第一個參數的格式腳本對應類型的其他參數...... 一般而言,在運行時完成。
printf
的家庭功能是可變參數函數,因爲他們都使用省略號...
這意味着任何類型的參數(一個或多個),只要...
而言可以被傳遞給該函數。有沒有限制由編譯器,因爲有沒有要求在類型的論點。編譯器不能施加任何類型安全規則,因爲省略號...
允許所有類型。該函數使用格式字符串到假設參數類型(即使有不匹配!!)。 格式字符串在運行時被讀取和解釋,此時編譯器不能做任何事情,如果有不匹配,因爲代碼已經編譯。所以這樣,這不是類型安全的。通過類型安全,我們通常意味着編譯器可以通過對(未評估的)表達式的類型強加規則來檢查程序的類型一致性。
請注意,如果存在不匹配(該函數無法計算出!),程序將進入未定義行爲區域,該程序的行爲不可預測,理論上可能發生任何事情。
您可以將相同的邏輯擴展到任何可變功能函數,如scanf
系列。
類型系統保證正確性與
std::ostream
但不printf
。 康拉德的回答就是一個例子,但類似printf("%ld\n", 7);
也斷了(假設
long
和int
是您的系統上不同大小)。它甚至可能與一個構建目標一起工作而失敗。試圖打印像size_t
這樣的typedefs有同樣的問題。這(有點)解決與某些編譯器所提供的診斷,但是,這並不與第二感幫助:在格式字符串中使用
兩個類型系統(運行時類型系統,以及代碼中使用的編譯時系統)不能自動保持同步。例如,
printf
與模板嚴重交互:template <typename T> void print(T t) { printf("%d\n",t); }
你不能讓這個正確的爲各類
T
- 你能做的最好的是static_cast<int>(t)
那麼它將無法編譯如果T是不可轉換爲int。比較template <typename T> void print(std::ostream& os, T t) { os << t << '\n'; }
,其選擇的
operator<<
爲具有一個任何T
正確過載。
通常,編譯器無法檢查來自printf的參數,甚至沒有參數計數,也不檢查它們是否適合格式字符串。他們是「優化」來完成這項工作,但是是一種特殊情況,可能會失敗。 實施例:
printf("%s %d\n", 1, "two", 3);
這將編譯(除非優化編譯器檢測故障),並在運行時,printf的將考慮第一個參數(1)的字符串和第二(「二」)一個整數。 printf甚至不會注意到有第三個參數,如果沒有足夠的參數,它們也不會注意到!
使用cout,編譯器必須爲您插入的每個變量選擇特定運算符< <。 實施例:
cout<<1<<"two"<<3<<endl;
編譯器必須改變這種在調用對應ostream&operator<<(int)
和ostream&operator<<(const char*)
(和也ostream&operator<<(ios&(*)(ios&))
)。
cout也會更快,因爲沒有格式字符串的運行時解釋。
- 1. 類型安全的printf
- 2. web.config比類更安全嗎?
- 3. cout和printf的
- 4. printf:這安全嗎?
- 5. 如何重寫printf到cout中
- 6. 安全地更改printf()以打印()?
- 7. 類比結構更安全嗎?
- 8. 如何wp_mail()比郵件更安全()
- 9. 螺紋安全std :: cout
- 10. 爲什麼引用變量類型比指針更安全?
- 11. C++ printf問題:如何安全地將char *傳遞給printf?
- 12. C++的cout像C的printf
- 13. 使用推力與printf/cout
- 14. cout如何區分基本類型?
- 15. 「類型安全」UUID?
- 16. 類型安全objectdatasources
- 17. 類型安全生成器:如何
- 18. 更換非類型與類型安全的泛型方法
- 19. 不安全的鑄造問題,如何投入類型安全?
- 20. 類型安全配置安全rendeing
- 21. ObjC選擇器/塊簽名比預期更強大但類型安全性更低? (自動 「不安全」 鑄造)
- 22. 如何在Jenkins中將安全類型從SSL更改爲TLS?
- 23. 在C++中使用printf()比cout有什麼主要優點?
- 24. 如何使這些動態類型函數類型安全?
- 25. 帶線程安全std :: cout的死鎖
- 26. COUT沒有指定類型
- 27. C#枚舉類型安全
- 28. Java和類型安全
- 29. 類型安全警告
- 30. 類型安全編碼
因爲我們顯式傳遞格式字符串假設如果我用'%f'拼寫'%d'然後 - 未定義的行爲。 –
[printf vs cout in C++]可能的副本(http://stackoverflow.com/questions/2872543/printf-vs-cout-in-c) – 0decimal0
由於您提到類型安全,請參閱http://stackoverflow.com/問題/ 4781819/printf-vs-stdcout和http://stackoverflow.com/questions/2017489/should-i-use-printf-in-my-c-code和... – devnull