ทำไม scanf () ต้องการ“% lf” เป็นสองเท่าเมื่อ printf () ไม่เป็นไรด้วยเพียงแค่“% f”


179

ทำไมมันจึงเป็นที่scanf()ต้องการlใน " %lf" เมื่ออ่านdoubleเมื่อprintf()สามารถใช้ " %f" โดยไม่คำนึงว่าอาร์กิวเมนต์เป็นdoubleหรือfloat?

รหัสตัวอย่าง:

double d;
scanf("%lf", &d);
printf("%f", d);

1
ฉันไม่เข้าใจว่าคุณหมายถึงอะไรโดยตัวชี้ที่นี่ ใน scanf เราส่งผ่าน & variable (ie) address เท่านั้นดังนั้นตัวชี้จะอยู่ที่ไหน

7
@deetchanya ใน C เมื่อคุณ "รับที่อยู่ของ" ตัวแปรที่มี&โอเปอเรเตอร์unary ผลลัพธ์ของการดำเนินการนั้นจะเป็นตัวชี้ไปยังตำแหน่งที่เก็บของตัวแปรในหน่วยความจำ scanfมันเป็นตัวชี้ที่ถูกส่งผ่านไปยัง
zwol

นี่เป็นอีกโพสต์ที่เกี่ยวข้องกับstackoverflow.com/questions/9291348/
vimalpt

คำตอบ:


207

เนื่องจาก C จะเลื่อนระดับการลอยตัวเป็นสองเท่าสำหรับฟังก์ชันที่รับอาร์กิวเมนต์ตัวแปร ชี้ยังไม่ได้เลื่อนตำแหน่งให้เป็นอะไรดังนั้นคุณควรจะใช้%lf, %lgหรือ%le(หรือ%laใน C99) ไปอ่านในคู่ผสม


26

ตั้งแต่С99การจับคู่ระหว่าง specifiers รูปแบบและประเภทอาร์กิวเมนต์จุดลอยตัวใน C มีความสอดคล้องระหว่างและprintf scanfมันคือ

  • %f สำหรับ float
  • %lf สำหรับ double
  • %Lf สำหรับ long double

มันเกิดขึ้นเพียงเพื่อว่าเมื่อการขัดแย้งของประเภทfloatจะถูกส่งผ่านเป็นพารามิเตอร์ variadic doubleข้อโต้แย้งดังกล่าวจะถูกแปลงโดยปริยายในการพิมพ์ นี่คือเหตุผลว่าทำไมในตัวprintfระบุรูปแบบ%fและ%lfเทียบเท่าและใช้แทนกันได้ ในprintfคุณสามารถ "ข้ามใช้" %lfด้วยfloatหรือกับ%fdouble

แต่ไม่มีเหตุผลที่จะทำจริง ๆ ในทางปฏิบัติ ไม่ได้ใช้%fเพื่อการขัดแย้งของประเภทprintf doubleมันเป็นนิสัยที่แพร่หลายเกิดขึ้นใน C89 / 90 ครั้ง แต่มันเป็นนิสัยที่ไม่ดี ใช้%lfในprintfสำหรับdoubleและให้%fสงวนไว้สำหรับfloatการขัดแย้ง


1
ฉันจะบอกว่าการใช้ %fใน printf นั้นเป็นนิสัยที่ดีเพราะรหัสของคุณใช้ได้เสมอในขณะที่การใช้%lfอาจล้มเหลวหากคอมไพเลอร์ไม่มีไลบรารี่ที่รองรับมาตรฐาน C99 น่าเสียดายที่สถานการณ์นั้นเกิดขึ้นจริง
MM

ตั้งแต่С99การจับคู่ระหว่าง specifiers รูปแบบและประเภทอาร์กิวเมนต์จุดลอยตัวใน C มีความสอดคล้องระหว่างและprintf scanf โปรดทราบว่านี่ไม่ได้หมายความว่าการใช้ตัวระบุรูปแบบเดียวกันหมายความว่าข้อมูลที่เขียนโดย a [f]printf()สามารถอ่าน[f]scanf()ได้ โดยทั่วไปการใช้ตัวระบุรูปแบบเดียวกันสำหรับscanf()ที่ใช้โดยprintf()จะไม่อ่านข้อมูลได้สำเร็จ ยกตัวอย่างเช่นการขยายพื้นที่ที่สามารถแทรกโดยprinf()'s "%d"รูปแบบระบุจะถูกข้ามไปโดยที่เดียวกัน"%d"ระบุรูปแบบในscanf()การโทร
Andrew Henle

16

scanfความต้องการที่จะรู้ว่าขนาดของข้อมูลที่ถูกชี้ไปที่โดย&dการกรอกข้อมูลได้อย่างถูกต้องในขณะที่ฟังก์ชั่น variadic ส่งเสริมลอยไปคู่ผสม (ไม่ได้ทั้งหมดแน่ใจว่าทำไม) ดังนั้นมักจะได้รับprintfdouble


1
ฟังก์ชั่น Variadic นั้นมีความเปราะบางมากเพราะจำเป็นต้องทราบชนิดและขนาดที่แน่นอนของพารามิเตอร์ทั้งหมดที่ส่งผ่านไปและมันไม่สามารถบังคับใช้สิ่งนี้ในเวลารวบรวม หากตัวแปรเป็นประเภทที่ไม่ถูกต้องจะอ่านค่าที่ไม่ถูกต้อง ถ้ามันมีขนาดไม่ถูกต้องตัวแปรทั้งหมดหลังจากนั้นก็จะถูกอ่านผิดเช่นกัน หากลอยได้สองขนาดแตกต่างกันก็จะทำให้เกิดปัญหาที่น่ารังเกียจและง่ายต่อการพลาดทุกชนิด
mwfearnley

7

เพราะอย่างอื่น scanf จะคิดว่าคุณกำลังส่งตัวชี้ไปยัง float ซึ่งมีขนาดเล็กกว่าหนึ่งเท่าและมันจะคืนค่าที่ไม่ถูกต้อง


2

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


5
float ถูกแปลงเป็น double ในกรณีนี้เนื่องจากอาร์กิวเมนต์เป็นส่วนหนึ่งของรายการอาร์กิวเมนต์ที่มีความยาวผันแปรการลอยจะไม่ถูกแปลงเป็นคู่ใน C เสมอไป
Robert Gamble

1
ในรุ่นภาษามาตรฐานก่อนค่าของภาษาที่floatได้รับการส่งเสริมโดยอัตโนมัติdoubleในการแสดงออก กฎนั้นถูกทอดทิ้งในมาตรฐาน C โดยทั่วไปfloatจะไม่ได้รับการเลื่อนระดับเป็นdoubleนิพจน์ มันจะได้รับการเลื่อนตำแหน่งdoubleเมื่อผ่านเป็นอาร์กิวเมนต์โต้แย้งซึ่งเป็นสิ่งที่เกิดขึ้นในกรณีนี้
AnT
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.