為什麼C語言的Hello,world都是用printf輸出而不是puts?

幾乎所有C語言教材的hello,world都是用printf輸出的。

我覺得printf是「格式化輸出」,僅僅輸出一個字元串是大材小用了,而且還要手動加"
"。

相比之下,puts含義明確(輸出一行文字),不用加"
"就自動換行,是輸出一行字最簡單的方式,為什麼不用它寫hello,world呢?

有些人寫代碼總是printf("%s
",s)而不是直接puts(s),我也不太理解。


用一行類似於printf("Hello World")的語句來開始學習一門編程語言。事實上不止是C語言,市面上幾乎所有語言的所有語言入門教程都是這麼乾的。我的理解是,向 丹尼斯·李奇 先生致敬,他當年為地球打開新世界的《The C Program Language》一書就是這麼乾的。至於他為什麼這麼干,我認為別的回答更有道理

至於為什麼大家不愛用puts(),恰恰是因為它的功能專註而單一,課本里並沒有側重於它,老師授課也沒有側重於它,考試也沒有側重於它。

真相往往就是這麼簡單。


8 main:
9 .LFB0:
10 .cfi_startproc
11 pushl %ebp
12 .cfi_def_cfa_offset 8
13 .cfi_offset 5, -8
14 movl %esp, %ebp
15 .cfi_def_cfa_register 5
16 andl $-16, %esp
17 subl $16, %esp
18 movl $.LC0, (%esp)
19 call puts #編譯器將printf優化為puts
20 leave
21 .cfi_restore 5
22 .cfi_def_cfa 4, 4
23 ret
24 .cfi_endproc


代碼可讀性比什麼都重要。用printf有以下幾個理由:

1. print本身有列印的意思,新手和其他語言使用者能很快理解這句話的意思。

2. printf傳入的參數就是實際的列印結果,你不需要再用人腦去模擬puts增加換行的過程。

3. 減少相似功能函數的混用。舉個簡單的例子,新手學c++的時候會cin一行之後用gets,然後gets得到的是個換行符。。同樣道理,混用puts和printf也會經常多個換行少個換行,最好統一。然而puts能替代printf么?顯然不行,那麼答案自然只有統一用printf。

最後我想說,在計算機如此發展,編譯器如此發達的今天,請不要太在意「非數量級」上的性能差異。程序的可讀性真的真的比什麼都重要。


殺雞就用牛刀,怎麼了?


沒有人說printf和fprintf是非安全函數嗎?程序員們小心點,這個函數經常是黑客的攻擊目標,尤其是列印的內容裡面有用戶輸入的信息的時候,分分鐘被黑客打破


如果只學一種輸出方法的話 printf比puts能應用的場合更多事實上調用puts的cost比調用printf小 但printf支持formatted string,支持不自動換行,所以適應性更廣。能用puts還用printf可能一是為了保持代碼的一致性 二是因為常年一致的用printf忘了puts的存在…

作為入門教材選用printf就是給讀者一種能輸出大多數東西的方法 因為顯然光知道printf可以 但光知道puts不行


有些人寫代碼總是printf("%s
",s)而不是直接puts(s),我也不太理解。

printf("%s
",s)確實是很蠢的一種寫法,【根據後來的個別回答,某些實現會把printf("%s
",s)自動優化為puts(s)。這說明連編譯器都對printf("%s
",s)看不下去了】

原因是很多人上來學的就是printf(),

有一種先入為主的慣性,

加上對自己的代碼質量沒有太高的要求,

所以只要輸出就想到用printf()。

類似的還有輸出新行符寫成printf("
")(譚浩強就一向如此),

而不是寫成putchar("
")。

======================================

幾乎所有C語言教材的hello,world都是用printf輸出的。

我覺得printf是「格式化輸出」,僅僅輸出一個字元串是大材小用了,而且還要手動加"
"。

相比之下,puts含義明確(輸出一行文字),不用加"
"就自動換行,是輸出一行字最簡單的方式,為什麼不用它寫hello,world呢?

你說得有一定道理。

問題在於你看的教材要講什麼以及講沒講。

就KR而言,在講hello,world時還介紹了
,以及

printf("hello,");
printf("world");
printf("
");

這種等價寫法。

這兩個知識是用puts()不勝任的。

比如,puts()本身如你所說,「不用加"
"就自動換行
」(實際是遇到輸出
),這就很難引入對
的介紹,因為不需要。如果硬要引入(比如在字元串中間加
)則顯得很不自然,而且很難解釋轉成
的問題。

用用puts()的另一個問題是沒法把"hello,world"分成幾段逐次輸出。而把"hello,world"分成幾段逐次輸出對於學習者深入理解「程序」這個概念、學習美化C程序格式以及領略C語言靈活的特點的是很有意義的。

So,如果你的教材介紹了相關的知識,那麼使用printf()講hello,world無可非議;如果沒介紹相關知識,那就是東施效顰,還不如用puts()。

=============

回答一下 @an Aaron 的疑問:

首先,printf("%s
",s)從思想上來說繞了一個彎子,它的意思是把一個字元串插入到%s處輸出,puts(s)則直截了當,就是輸出字元串;

其次,前者要用兩個實參,後者只用一個。寫程序的人都知道,寫得越多出錯的可能性越大;

第三,代碼哪個簡潔是一目了然的;

第四,printf()與puts()函數的實現方法不同,前者要複雜得多,至少要多一個對格式字元串分析的步驟。所以從執行效率上來看,顯然也是後者為優。調用時空間方面後者也同樣為優。

============================

至於 @pansz 所說的

因為工程上經常需要用宏重定義printf,來實現將輸出定向到其它目標的目的。如果使用多個不同的輸出函數就會顯得很麻煩。"

我不能確信我是否確實理解了他所說的是怎樣一種情況。據我所知,puts()同樣能完成重新定向的功能。

我希望@pansz 能進一步補充說明一下那樣寫的前提條件。


格式化輸出用的太頻煩了,習慣了,此外性能差別相當小


一開始別在意這種問題 編譯器會轉成puts putc 這種


puts太弱了,只能輸出一個字元串,

其他很多語言都有字元串相加,這樣基本的輸出就變得強大了許多,


KR的書的第二個例子是攝氏溫度與華氏溫度的轉換,所以啊


因為puts必然可以被printf取代,但printf可不是總能被puts取代的(廢話)

既然沒必要我為什麼要增加自己的學習負擔?我只要學會printf就夠了,根本不需要去學puts

(我還是剛剛Google了一下,才確認了puts會在結尾自動加


C語言第一行代碼就是printf。大家都有先入為主的概念。


看一看各大語言的Hello World怎麼寫……

/* C */
#include &
int main(void) {
printf("Hello, world!");
return 0;
}

REM BASIC
PRINT "HELLO, WORLD!"

print("Hello, world!") # Python

print "Hello, world!" # Perl

Form1.Print "Hello, world!" "Visual Basic

// Java
public class hello {
public static void main(String args[]) {
System.out.print("Hello, world!");
}
}

於是,我們發現了一件事——輸出語句基本都用類似Print的單詞。


因為不知道還有這麼個函數


puts函數功能雖然簡單,put的英文含義對於非英文母語也不難,但是並不夠。。。不夠計算機術語化

print的更為明確的英文含義更符合這個場景。

另外,我也贊同匿名用戶的說話,puts太過功能單一,而我們用hello world入門後乾的事情可不是puts能搞定的,還是用最常用的print來寫hello world吧


因為 puts (3)是配合gets (3)使用的, 因為gets (3)存在安全問題, GNU C建議用 fgets (3) / fputs (3);

所以, 輪不到puts (3);

ps. printf 家族函數很好用;


我覺得,用printf()是因為它的表面字義!讓初學者更容易理解接受!

哪有那麼複雜!


1)只用一個函數搞定各種輸出方便又完美啊。

2)puts自動加的換行,萬一是windows風格的,沒有精確的安全感啊。

不僅puts少用,類似fputs寧願用fprintf,否則代碼總有隱患的時候


printf("printf涵蓋了puts的功能,如無必要,勿增實體。
")

puts("雖然puts好像更美觀,但它唯一的優勢就是美觀,所以不常用。")

printf("如果你用了不常用的puts,恐怕後果是puts與printf混用,丑。
")

puts("該puts的時候printf還可以菊里力爭一下,該用printf的時候……啊,一般也不能用puts。")


推薦閱讀:

C#與VC++在桌面軟體的開發比較?
一行 JS (以分號結束)能實現什麼喪心病狂的功能?
Matlab求一個矩陣中所有元素的平方和,兩種循環寫法為什麼性能相差很大?
C 語言指針的指針和二維數組的區別?
如何生成rest api文檔?

TAG:程序員 | 編程 | C編程語言 | HelloWorld程序 |