Định dạng đúng định dạng cho double trong printf


482

Định dạng định dạng chính xác cho doubleprintf là gì? Là nó %fhay là nó %lf? Tôi tin nó %f, nhưng tôi không chắc chắn.

Mẫu mã

#include <stdio.h>

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

19
Nếu bạn bị mắc kẹt với thư viện C89, "%lf"không xác định; trong các thư viện C99 và C11, nó được định nghĩa giống như "%f".
PMG

1
Biến thể của bạn là chính xác như nó từng có. %lflà định dạng định dạng chính xác cho double. Nhưng nó đã trở thành như vậy trong C99. Trước đó người ta phải sử dụng %f.
AnT

Câu trả lời:


626

"%f"là định dạng đúng (hoặc ít nhất một) cho một đôi. Có không có định dạng cho một float, bởi vì nếu bạn cố gắng để vượt qua một floattới printf, nó sẽ được thăng chức doubletrước khi printfnhận nó 1 . "%lf"cũng được chấp nhận theo tiêu chuẩn hiện tại - lđược chỉ định là không có hiệu lực nếu được theo sau bởi công fcụ xác định chuyển đổi (trong số những người khác).

Lưu ý rằng đây là một nơi mà các printfchuỗi định dạng khác nhau đáng kể so với các chuỗi định dạng scanf(và fscanf, v.v.). Đối với đầu ra, bạn đang đi qua một giá trị , mà sẽ được đề bạt từ floatđến doublekhi thông qua như là một tham số variadic. Đối với đầu vào bạn đang truyền một con trỏ không được quảng bá, vì vậy bạn phải cho biết scanfbạn muốn đọc a floathay a double, vì vậy scanf, %fcó nghĩa là bạn muốn đọc một float%lfcó nghĩa là bạn muốn đọc một double(và, cho những gì nó giá trị, cho a long double, bạn sử dụng %Lfcho một trong hai printfhoặc scanf).


1. C99, §6.5.2.2 / 6: "Nếu biểu thức biểu thị hàm được gọi có loại không bao gồm nguyên mẫu, các quảng cáo số nguyên được thực hiện trên mỗi đối số và các đối số có kiểu float được tăng lên gấp đôi. Chúng được gọi là các chương trình khuyến mãi đối số mặc định. " Trong C ++, từ ngữ hơi khác một chút (ví dụ: nó không sử dụng từ "nguyên mẫu") nhưng hiệu quả là như nhau: tất cả các tham số biến đổi đều trải qua các chương trình khuyến mãi mặc định trước khi chúng được hàm nhận.


8
Lưu ý rằng g++từ chối %lfkhi biên dịch với -Wall -Werror -pedantic:error: ISO C++ does not support the ‘%lf’ gnu_printf format
kynan

2
@kynan: Nếu vậy (tại leas giả sử phiên bản hiện tại của g ++), đó là một lỗi trong g ++. Đối với C89 / 90 và C ++ 98/03, cho phép llà một phần mở rộng. Các tiêu chuẩn C99 / 11 và C ++ 11 yêu cầu triển khai để cho phép nó.
Jerry Coffin

1
Thật kỳ lạ, scanf không muốn doubleđại diện bởi %lf: nó phàn nàn rằng nó mong đợi float *và được tìm thấy double *với chỉ %f.
Eric Dand

1
@JerryCoffin g ++ vẫn mặc định ở chế độ g ++ 98
MM

5
@EricDand Đó là bởi vì scanfmất con trỏ đến nơi lưu trữ những gì nó đọc, vì vậy nhu cầu để biết lớn như thế nào không gian là nhọn-at là, trong khi printfmất các giá trị bản thân, và "chương trình khuyến mãi đối số mặc định" có nghĩa là cả hai kết thúc lên như doubles, do đó llà về cơ bản là tùy chọn.
TripeHound

63

Với tiêu chuẩn C99 (cụ thể là dự thảo N1256 ), các quy tắc phụ thuộc vào loại chức năng: fprintf (printf, sprintf, ...) hoặc scanf.

Dưới đây là các phần có liên quan được trích xuất:

Lời tựa

Phiên bản thứ hai này hủy bỏ và thay thế phiên bản đầu tiên, ISO / IEC 9899: 1990, được sửa đổi và sửa chữa bởi ISO / IEC 9899 / COR1: 1994, ISO / IEC 9899 / AMD1: 1995 và ISO / IEC 9899 / COR2: 1996. Những thay đổi lớn từ phiên bản trước bao gồm:

  • %lf chỉ định chuyển đổi được phép trong printf

7.19.6.1 fprintfHàm

7 Các sửa đổi độ dài và ý nghĩa của chúng là:

l (ell) Chỉ định rằng (...) không có hiệu lực đối với chỉ định chuyển đổi a, A, e, E, f, F, g hoặc G.

L Chỉ định rằng một chỉ định chuyển đổi a, A, e, E, f, F, g hoặc G sau áp dụng cho một đối số kép dài.

Các quy tắc tương tự được chỉ định để fprintfáp dụng cho printf, sprintfvà các chức năng tương tự.

7.19.6.2 fscanfHàm

11 Các sửa đổi độ dài và ý nghĩa của chúng là:

l (ell) Chỉ định rằng (...) rằng a sau a, A, e, E, f, F, g hoặc G chỉ định chuyển đổi áp dụng cho một đối số có con trỏ kiểu gấp đôi;

L Chỉ định rằng một chỉ định chuyển đổi a, A, e, E, f, F, g hoặc G sau áp dụng cho một đối số có con trỏ kiểu để nhân đôi dài.

12 Các chỉ định chuyển đổi và ý nghĩa của chúng là: a, e, f, g Ghép một số dấu phẩy động được ký tùy ý, (...)

14 Các chỉ định chuyển đổi A, E, F, G và X cũng hợp lệ và hoạt động tương tự như, a, e, f, g và x.

Câu chuyện dài, dành cho fprintfcác nhà đầu cơ sau đây và các loại tương ứng được chỉ định:

  • %f -> gấp đôi
  • %Lf -> dài gấp đôi.

và cho fscanfnó là:

  • %f -> phao
  • %lf -> gấp đôi
  • %Lf -> dài gấp đôi.

25

Nó có thể %f, %ghoặc %etùy thuộc vào cách bạn muốn số được định dạng. Xem ở đây để biết thêm chi tiết. Công cụ lsửa đổi là bắt buộc scanfvới double, nhưng không phải trong printf.


1
Công cụ lsửa đổi -1: (chữ thường) dành cho các loại số nguyên ( cplusplus.com/reference/cl Library / cstdio / printf ) và Ldành cho các loại dấu phẩy động. Ngoài ra, công cụ Lsửa đổi mong đợi một long double, không phải là đơn giản double.
dùng470379

10
user470379: Vậy đâu là mâu thuẫn với câu trả lời của tôi? Tôi đã không nói rằng lkhông cần thiết printfcho double.
vitaut

16

Định dạng %lflà một printfđịnh dạng hoàn toàn chính xác cho double, chính xác như bạn đã sử dụng nó. Không có gì sai với mã của bạn.

Định dạng %lftrong printfkhông được hỗ trợ trong các phiên bản cũ (trước C99) của ngôn ngữ C, điều này tạo ra sự "không nhất quán" hời hợt giữa các chỉ định định dạng cho doubletrong printfscanf. Sự không nhất quán bề ngoài đó đã được sửa trong C99.

Bạn không bắt buộc phải sử dụng %lfvới doubleprintf. Bạn cũng có thể sử dụng %f, nếu bạn thích ( %lf%ftương đương trong printf). Nhưng trong C hiện đại, nó có ý nghĩa hoàn hảo để thích sử dụng %fvới float, %lfvới double%Lfvới long double, nhất quán trong cả hai printfscanf.


Với scanf(), "%f", "%lf"phù hợp với một float *, double *, không float, doublenhư ngụ ý của dòng cuối cùng.
chux - Phục hồi Monica

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.