ตัวระบุรูปแบบที่ถูกต้องสำหรับ double ใน printf


482

ตัวระบุรูปแบบที่ถูกต้องสำหรับdoubleใน printf คืออะไร มัน%fหรือมันคือ%lf? ฉันเชื่อว่ามัน%fแต่ฉันไม่แน่ใจ

ตัวอย่างโค้ด

#include <stdio.h>

int main()
{
   double d = 1.4;
   printf("%lf", d); // Is this wrong?
}

19
หากคุณติดกับ C89 ไลบรารี่"%lf"จะไม่ได้กำหนด; ใน C99 และ C11 "%f"ห้องสมุดมันถูกกำหนดให้เป็นเช่นเดียวกับ
pmg

1
ตัวแปรของคุณถูกต้องเท่าที่เคยได้รับ ระบุเป็นรูปแบบที่ถูกต้องสำหรับ%lf doubleแต่มันก็เป็นเช่นนั้นใน C99 %fก่อนที่เราจะต้องใช้
AnT

คำตอบ:


626

"%f"เป็นรูปแบบที่ถูกต้อง (หรืออย่างน้อยหนึ่ง) สำหรับคู่ มีเป็นรูปแบบไม่มีfloatเพราะถ้าคุณพยายามที่จะผ่านfloatไปprintfก็จะได้รับการเลื่อนตำแหน่งให้เป็นdoubleก่อนที่จะprintfได้รับมัน1 "%lf"เป็นที่ยอมรับได้ภายใต้มาตรฐานปัจจุบัน - lระบุว่าไม่มีผลหากตามด้วยตัวfระบุการแปลง

โปรดทราบว่านี่เป็นที่เดียวที่printfสตริงการจัดรูปแบบแตกต่างจากสตริงการจัดรูปแบบscanf(และfscanfอื่น ๆ ) อย่างมาก สำหรับผลลัพธ์คุณกำลังส่งค่าซึ่งจะเลื่อนระดับจากfloatเป็นdoubleเมื่อผ่านเป็นพารามิเตอร์ Variadic สำหรับการป้อนข้อมูลที่คุณผ่านตัวชี้ซึ่งไม่ได้รับการส่งเสริมการลงทุนเพื่อให้คุณมีที่จะบอกscanfว่าคุณต้องการที่จะอ่านfloatหรือdoubleเพื่อให้scanf, %fวิธีการที่คุณต้องการที่จะอ่านfloatและ%lfวิธีการที่คุณต้องการที่จะอ่านdouble(และสำหรับสิ่งที่มันเป็น คุ้มค่าสำหรับlong doubleคุณใช้%Lfเพื่ออย่างใดอย่างหนึ่งprintfหรือscanf)


1. C99, §6.5.2.2 / 6: "ถ้านิพจน์ที่แสดงถึงฟังก์ชั่นที่เรียกว่ามีประเภทที่ไม่รวมต้นแบบโปรโมชั่นจำนวนเต็มจะดำเนินการในแต่ละอาร์กิวเมนต์และอาร์กิวเมนต์ที่มีประเภทลอยได้รับการเลื่อนระดับเป็นสองเท่า สิ่งเหล่านี้เรียกว่าการเลื่อนระดับอาร์กิวเมนต์เริ่มต้น " ใน C ++ ถ้อยคำแตกต่างกันบ้าง (เช่นมันไม่ได้ใช้คำว่า "ต้น") แต่ผลจะเหมือนกัน: พารามิเตอร์ตัวแปรทั้งหมดจะได้รับการเลื่อนระดับเริ่มต้นก่อนที่พวกเขาจะได้รับฟังก์ชั่น


8
โปรดทราบว่าจะg++ปฏิเสธ%lfเมื่อรวบรวมกับ-Wall -Werror -pedantic:error: ISO C++ does not support the ‘%lf’ gnu_printf format
kynan

2
@ kynan: ถ้าเป็นเช่นนั้น (ที่สันนิษฐานว่าเป็นรุ่นปัจจุบันของ g ++) นั่นเป็นจุดบกพร่องใน g ++ สำหรับ C89 / 90 และ C ++ 98/03 การอนุญาตlคือส่วนขยาย มาตรฐาน C99 / 11 และ C ++ 11 ต้องการการติดตั้งเพื่อให้สามารถใช้ได้
Jerry Coffin

1
อยากรู้อยากเห็นscanf ไม่ลงdoubles แสดงโดย%lf: มันบ่นว่ามันคาดfloat *และพบว่ามีเพียงdouble * %f
Eric Dand

1
@JerryCoffin g ++ ยังคงเป็นค่าเริ่มต้นที่โหมด g ++ 98
MM

5
@EricDand นั่นเป็นเพราะscanfต้องใช้ตัวชี้ไปยังที่จัดเก็บสิ่งที่มันอ่านเพื่อตอบสนองความต้องการที่จะรู้ว่าวิธีการใหญ่พื้นที่เป็นแหลมที่เป็นในขณะที่printfการใช้ค่าตัวเองและ "โปรโมชั่นการโต้เถียงเริ่มต้น" หมายถึงการสิ้นสุดทั้งสองขึ้นเป็นdoubles เพื่อให้lเป็น ตัวเลือกเป็นหลัก
TripeHound

63

รับมาตรฐานC99 (เช่นร่างN1256 ) กฎขึ้นอยู่กับชนิดของฟังก์ชัน: fprintf (printf, sprintf, ... ) หรือ scanf

นี่คือส่วนที่เกี่ยวข้องสกัด:

คำนำ

ฉบับที่สองนี้ยกเลิกและแทนที่ฉบับที่หนึ่ง ISO / IEC 9899: 1990 ซึ่งแก้ไขและแก้ไขโดย ISO / IEC 9899 / COR1: 1994, ISO / IEC 9899 / AMD1: 1995 และ ISO / IEC 9899 / COR2: 1996 การเปลี่ยนแปลงที่สำคัญจากรุ่นก่อนหน้ารวมถึง:

  • %lf ตัวระบุการแปลงที่ได้รับอนุญาตใน printf

7.19.6.1 fprintfฟังก์ชั่น

7ตัวดัดแปลงความยาวและความหมายคือ:

l (ell) ระบุว่า (... ) ไม่มีผลต่อตัวระบุการแปลง a, A, e, E, f, F, g หรือ G

Lระบุว่าตัวระบุการแปลง a, A, e, E, f, F, g หรือ G ใช้กับอาร์กิวเมนต์คู่ยาว

กฎเดียวกันที่ระบุไว้สำหรับfprintfนำไปใช้สำหรับprintf, sprintfและฟังก์ชั่นที่คล้ายกัน

7.19.6.2 fscanfฟังก์ชั่น

11ตัวดัดแปลงความยาวและความหมายคือ:

l (ell) ระบุว่า (... ) ที่ตัวระบุการแปลง a, A, e, E, f, F, g หรือ G ต่อไปนี้ใช้กับอาร์กิวเมนต์ที่มีชนิดตัวชี้เป็นสองเท่า

Lระบุว่าตัวระบุการแปลง a, A, e, E, f, F, g หรือ G ใช้กับอาร์กิวเมนต์ที่มีตัวชี้ประเภทเป็นสองเท่าแบบยาว

12ตัวระบุการแปลงและความหมายคือ: a, e, f, g ตรงกับหมายเลขจุดลอยตัวที่ลงนามเลือก (... )

14ตัวระบุการแปลง A, E, F, G และ X ก็ใช้ได้เช่นกัน, ตามลำดับ, a, e, f, g และ x

เรื่องสั้นที่สั้นสำหรับfprintfตัวระบุต่อไปนี้และประเภทที่เกี่ยวข้องมีการระบุไว้:

  • %f -> สองเท่า
  • %Lf -> ยาวเป็นสองเท่า

และfscanfมันคือ:

  • %f -> ลอย
  • %lf -> สองเท่า
  • %Lf -> ยาวเป็นสองเท่า

25

มันอาจจะเป็น%f, %gหรือ%eขึ้นอยู่กับว่าคุณต้องการจำนวนการจัดรูปแบบ ดูที่นี่สำหรับรายละเอียดเพิ่มเติม lปรับปรุงจะต้องscanfมีแต่ไม่ได้อยู่ในdoubleprintf


1
-1: l(ตัวพิมพ์เล็ก) ตัวดัดแปลงสำหรับประเภทจำนวนเต็ม ( cplusplus.com/reference/clibrary/cstdio/printf ) และLสำหรับประเภทจุดลอย นอกจากนี้การLปรับปรุงคาดว่าไม่ธรรมดาlong double double
user470379

10
user470379: ดังนั้นความขัดแย้งกับคำตอบของฉันอยู่ที่ไหน ยังไม่ได้ผมบอกว่าlไม่จำเป็นต้องใช้ในสำหรับprintf double
vitaut

16

รูปแบบ%lfเป็นรูปแบบที่ถูกต้องอย่างสมบูรณ์printfสำหรับdoubleตรงตามที่คุณใช้ ไม่มีอะไรผิดปกติกับรหัสของคุณ

รูปแบบ%lfในการprintfไม่ได้รับการสนับสนุนในรุ่นเก่า (Pre-C99) ของภาษา C ซึ่งสร้างผิวเผิน "ไม่สอดคล้องกัน" ระหว่าง specifiers รูปแบบdoubleในและprintf scanfความไม่สอดคล้องกันตื้น ๆ นั้นได้รับการแก้ไขใน C99

คุณไม่จำเป็นต้องใช้%lfกับในdouble printfคุณสามารถใช้%fเช่นกันหากคุณต้องการ ( %lfและ%fเทียบเท่าprintf) แต่ในปัจจุบัน C มันทำให้รู้สึกดีที่จะชอบที่จะใช้%fกับfloat, %lfด้วยdoubleและ%Lfมีlong doubleอย่างต่อเนื่องทั้งในและprintfscanf


ด้วยscanf(), "%f", "%lf"ตรงกับfloat *, double *ไม่float, doubleเป็นโดยนัยบรรทัดสุดท้าย
chux - Reinstate Monica

9

%Lf(หมายเหตุทุนL) เป็นตัวระบุรูปแบบสำหรับคู่ยาว

สำหรับธรรมดาdoublesอย่างใดอย่างหนึ่ง%e, %E, %f, %gหรือ%Gจะทำ


ความแตกต่างระหว่าง%gและ%Gคืออะไร
yanpas

@yanpas ตัวพิมพ์เล็ก / ตัวพิมพ์ใหญ่สำหรับสัญลักษณ์เลขชี้กำลังตามลำดับ
Frédéric Hamidi

ขออภัย% g และ% G ทำสัญลักษณ์ E เอาต์พุต พวกเขายังส่งออก INF และ inf ในกรณีต่าง ๆ
yanpas
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.