อะไรคือความแตกต่างระหว่าง printf () และ put () ใน C?


176

ฉันรู้ว่าคุณสามารถพิมพ์ด้วยและprintf() puts()ฉันยังสามารถเห็นว่าprintf()ช่วยให้คุณสามารถแก้ไขตัวแปรและทำการจัดรูปแบบได้

เป็นเพียงรุ่นดั้งเดิมputs() printf()มันควรจะใช้สำหรับทุก ๆ ที่เป็นไปได้printf()หรือไม่



47
เพียงแค่ทราบเกี่ยวกับการใช้ printf แทนการใส่: ไม่เคยทำprintf(variable)เพื่อพิมพ์สตริง ใช้หรือputs(variable) printf("%s', variable)มีความเสี่ยงด้านความปลอดภัยในการใช้สตริงรูปแบบตัวแปร: หากตัวแปรสามารถเขียนได้โดยผู้โจมตีพวกเขาสามารถโจมตีโปรแกรมโดยใช้สตริงรูปแบบ
Zan Lynx

คำตอบ:


141

putsง่ายกว่าprintfแต่โปรดทราบว่าอดีตจะต่อท้ายบรรทัดใหม่โดยอัตโนมัติ หากนั่นไม่ใช่สิ่งที่คุณต้องการคุณสามารถfputsสตริงของคุณเพื่อ stdout printfหรือการใช้งาน


8
ฉันคิดว่ามันเป็นสิ่งสำคัญเช่นกันที่จะกล่าวถึงอาร์กิวเมนต์เพิ่มเติมที่ printf ใช้สำหรับการเพิ่มตัวแปรเพิ่มเติมลงในสตริงเอาท์พุท
Erutan409

99

(นี่เป็นการชี้ให้เห็นในความคิดเห็นโดย Zan Lynx แต่ฉันคิดว่ามันสมควรได้รับผู้ลี้ภัย - เนื่องจากคำตอบที่ยอมรับไม่ได้กล่าวถึง)

ความแตกต่างที่สำคัญระหว่างputs(mystr);และprintf(mystr);ที่อยู่ในหลังอาร์กิวเมนต์ที่ถูกตีความว่าเป็นสตริงการจัดรูปแบบ ผลลัพธ์มักจะเหมือนกัน (ยกเว้นสำหรับบรรทัดใหม่ที่เพิ่ม) หากสตริงไม่มีอักขระควบคุมใด ๆ ( %) แต่ถ้าคุณไม่สามารถวางใจได้ (ถ้าmystrเป็นตัวแปรแทนที่จะเป็นตัวอักษร) คุณไม่ควร ใช้มัน

ดังนั้นจึงเป็นอันตรายโดยทั่วไป - ผิดแนวคิด- การส่งผ่านสตริงแบบไดนามิกเป็นอาร์กิวเมนต์เดียวของprintf:

  char * myMessage;
  // ... myMessage gets assigned at runtime, unpredictable content
  printf(myMessage);  // <--- WRONG! (what if myMessage contains a '%' char?) 
  puts(myMessage);    // ok
  printf("%s\n",myMessage); // ok, equivalent to the previous, perhaps less efficient

เช่นเดียวกับfputsvs fprintf(แต่fputsไม่เพิ่มบรรทัดใหม่)


ในทางใดจะใช้printf()มีประสิทธิภาพน้อยกว่า? ในเวลาทำงาน? ในเวลารวบรวม?
แฟรงคลิ

10
@franklin ที่ runtime เนื่องจากprintfต้องแยกวิเคราะห์สตริงรูปแบบ อย่างไรก็ตามสิ่งนี้ควรไม่เกี่ยวข้องตามปกติ นอกจากนี้คอมไพเลอร์ฉลาดสามารถเพิ่มประสิทธิภาพนี้และแทนที่printfด้วยการเรียกร้องให้puts
leonbloy

33

นอกเหนือจากการจัดรูปแบบแล้วputsส่งคืนจำนวนเต็มที่ไม่ใช่ค่าลบหากสำเร็จหรือEOFหากไม่สำเร็จ ในขณะที่printfส่งกลับจำนวนของตัวอักษรที่พิมพ์ (ไม่รวมถึง null ท้าย)


16

ในกรณีที่เรียบง่ายแปลงคอมไพเลอร์โทรไปที่จะโทรไปprintf()puts()

ตัวอย่างเช่นรหัสต่อไปนี้จะถูกรวบรวมไปยังรหัสการชุมนุมที่ฉันแสดงต่อไป

#include <stdio.h>
main() {
    printf("Hello world!");
    return 0;
}
push rbp
mov rbp,rsp
mov edi,str.Helloworld!
call dword imp.puts
mov eax,0x0
pop rbp
ret

ในตัวอย่างนี้ผมใช้ GCC รุ่น 4.7.2 gcc -o hello hello.cและเรียบเรียงมากับตัว


9
และสิ่งที่เกี่ยวกับบรรทัดใหม่ที่ทำให้สถานที่ใน stdout?
zubergu

1
มันควรจะเป็นprintf("Hello world!\n");gcc อย่างแน่นอนแปลว่าจะทำให้ เนื่องจากเป็นข้อความเก่าฉันจะแก้ไขเอง
Rafael Almeida

2
คุณอ่านรหัสประกอบหลังจากรวบรวมรหัส C ได้อย่างไร
Koray Tugay

3
@KorayTugay: -save-tempsตัวเลือกสำหรับ gcc ทำเช่นนั้น
schaiba

คุณสามารถใช้เครื่องมือเช่น gdb เพื่อแยกไบนารี
Ivan Kaloyanov

10

ขวาอาจจะคิดว่าเป็นรุ่นที่มีประสิทธิภาพมากขึ้นของprintf ให้ความสามารถในรูปแบบตัวแปรสำหรับการส่งออกโดยใช้ specifiers รูปแบบเช่น, , ฯลฯ ...putsprintf%s%d%lf


10

ในประสบการณ์ของฉันprintf()ลากรหัสมากกว่าputs()โดยไม่คำนึงถึงสตริงรูปแบบ

printfถ้าฉันไม่จำเป็นต้องมีการจัดรูปแบบที่ฉันไม่ได้ใช้ อย่างไรก็ตามfwriteเพื่อให้stdoutทำงานได้เร็วกว่าputsมาก

static const char my_text[] = "Using fwrite.\n";
fwrite(my_text, 1, sizeof(my_text) - sizeof('\0'), stdout);

หมายเหตุ: ต่อความคิดเห็น '\ 0' เป็นค่าคงที่จำนวนเต็ม การแสดงออกที่ถูกต้องควรจะsizeof(char)เป็นตามที่ระบุโดยความคิดเห็น


2
"fwrite to stdout ทำงานได้เร็วกว่าการทำมาก" - อะไรคือสาเหตุที่เป็นไปได้?
Antony Hatchkins

6
@AntonyHatchkins ปกติแล้วมันจะไม่ "เร็ว" มากนัก อย่างไรก็ตาม put () จะต้องทำการเรียก strlen () ทุกครั้งบนสตริงของคุณในขณะที่ถ้าขนาดเป็นที่รู้จักกับ fwrite () มันสามารถหลีกเลี่ยงได้ นั่นเป็นสิ่งเดียวที่ทำให้เกิดความแตกต่างของประสิทธิภาพ
วิซ

8
คำตอบนี้ไม่ถูกต้อง '\0'มีประเภทดังนั้นในระบบส่วนใหญ่นี้จะพิมพ์int Using fwritหากคุณต้องการพิมพ์ 1 ไบต์ที่น้อยกว่าให้ใช้ 1 sizeof (char)ซึ่งน่าจะเป็นสิ่งที่คุณตั้งใจจะรับประกันว่าจะเป็น 1
แบรดลีย์การ์แกน

8
int puts(const char *s);

puts ()เขียนสตริง s และบรรทัดใหม่ต่อท้ายไปยัง stdout

int printf(const char *format, ...);

ฟังก์ชันprintf ()เขียนเอาต์พุตไปยัง stdout ภายใต้การควบคุมของสตริงรูปแบบที่ระบุว่าจะมีการแปลงอาร์กิวเมนต์ที่ตามมาสำหรับเอาต์พุตอย่างไร

ฉันจะใช้โอกาสนี้เพื่อขอให้คุณอ่านเอกสาร


5

ฟังก์ชัน printf () ใช้เพื่อพิมพ์ทั้งสตริงและตัวแปรไปยังหน้าจอในขณะที่ฟังก์ชัน put () อนุญาตให้คุณพิมพ์สตริงไปยังหน้าจอของคุณเท่านั้น


2

putsเป็นทางเลือกที่ง่ายและเพิ่มบรรทัดใหม่ในตอนท้ายและprintfเขียนเอาต์พุตจากสตริงที่จัดรูปแบบ

โปรดดูเอกสารสำหรับและputs printf

ฉันจะแนะนำให้ใช้เฉพาะprintfเช่นนี้เป็นสอดคล้องกันมากขึ้นกว่าวิธีการเปลี่ยนเช่นถ้าคุณกำลัง debbugging มันเป็น painfull น้อยที่จะค้นหา printfs ทั้งหมดกว่าและputs printfเวลาส่วนใหญ่ที่คุณต้องการส่งออกตัวแปรในงานพิมพ์ของคุณเช่นกันดังนั้นputsส่วนใหญ่จะใช้ในรหัสตัวอย่าง


1

เมื่อเปรียบเทียบputs()และprintf()แม้ว่าจะใช้หน่วยความจำของพวกเขาคือเกือบจะเหมือนกันต้องใช้เวลามากขึ้นเมื่อเทียบกับputs()printf()


โปรดเพิ่มคำอธิบายให้กับคำตอบของคุณเพื่อให้ผู้อื่นสามารถเรียนรู้ได้ - คุณมีแหล่งข้อมูลที่น่าเชื่อถือสำหรับการอ้างสิทธิ์นั้นหรือไม่? หรือเหตุผลบางอย่างที่จะอธิบายความแตกต่างนี้
Nico Haase
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.