Правильний специфікатор формату для подвійного в printf


480

Для чого правильний специфікатор формату 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

Відповіді:


624

"%f"це (або принаймні один) правильний формат для подвійного. Там немає неформат для float, тому що якщо ви спробуєте пропускати floatдо printf, він буде призначений , doubleперш ніж printfйого отримає 1 . "%lf"також є прийнятним згідно з чинним стандартом - значення lзадається таким, що не має ефекту, якщо слідує за fспецифікатором перетворення (серед інших).

Зауважте, що це одне місце, за яким printfрядки формату суттєво відрізняються від рядків формату scanffscanfт.д.). Для виводу ви передаєте значення , яке буде переведено з floatу той doubleмомент, коли він буде переданий як варіативний параметр. Для введення ви передаєте вказівник , який не рекламується, тому ви повинні сказати, scanfчи хочете ви прочитати a floatчи a double, так для scanf, %fозначає, що ви хочете прочитати a floatі %lfозначає, що ви хочете прочитати double(і для чого це варто, для a long double, ви використовуєте %Lfабо для, printfабо scanf).


1. C99, §6.5.2.2 / 6: "Якщо вираз, який позначає викликану функцію, має тип, який не включає прототип, цілі промоції виконуються на кожному аргументі, а аргументи, які мають тип float, сприяють подвоєнню. Вони називаються просуваннями аргументів за замовчуванням. " У C ++ формулювання дещо інше (наприклад, в ньому не використовується слово "прототип"), але ефект той самий: всі варіативні параметри зазнають промоції за замовчуванням до того, як їх отримає функція.


8
Зауважте, що g++відхиляє %lfпри компілюванні з -Wall -Werror -pedantic:error: ISO C++ does not support the ‘%lf’ gnu_printf format
kynan

2
@kynan: Якщо так (у leas припускаючи поточну версію g ++), це помилка в g ++. Для C89 / 90 та C ++ 98/03, дозволяючи lбуло розширенням. Стандарти C99 / 11 і C ++ 11 вимагають впровадження, щоб це дозволяло.
Джеррі Труну

1
Цікаво, scanf що хоче, doubleщоб його представляли %lf: він скаржиться на те, що очікував float *і знайшов double *справедливим %f.
Ерік Данд

1
@JerryCoffin g ++ як і раніше за замовчуванням переходить у режим g ++ 98
MM

5
@EricDand Це тому , що scanfприймає покажчики , де зберігати те , що він читає, тому потреба знати , наскільки великим є простір вказуємо на це, в той час як printfприймає самі значення, а «акцію аргументів по замовчуванням» означає , як в кінцевому підсумку , як doubleз, так що 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з double, але не в printf.


1
-1: l( малий ) модифікатор призначений для цілих типів ( cplusplus.com/reference/clibrary/cstdio/printf ) і Lпризначений для типів з плаваючою комою. Крім того, Lмодифікатор очікує а long double, а не звичайну double.
user470379

10
user470379: Тож де суперечність моїй відповіді? Хіба я не казав, що lце не потрібно printfдля double.
vitaut

15

Формат %lf- це абсолютно правильний printfформат double, точно такий, як ви його використовували. У вашому коді нічого поганого.

Формат %lfв printfне підтримувався в старих (до C99) версіях мови C, що створило поверхневу "невідповідність" між специфікаторами формату для doubleв printfі scanf. Ця поверхнева неузгодженість була зафіксована у С99.

Ви не повинні використовувати %lfз doubleв printf. Ви також можете використовувати %f, якщо ви хочете ( %lfі %fце еквівалентно printf). Але в сучасному С має ідеальний сенс віддавати перевагу використанню %fз float, %lfіз doubleта %Lfз long double, послідовно в обох printfта scanf.


З scanf(), "%f", "%lf"Збіг float *, double *, чи не float, doubleяк випливає з останнього рядка.
chux

9

%Lf(зверніть увагу на капітал L) - специфікатор формату для довгих пар .

Для рівнини doubles, або %e, %E, %f, %gабо %Gбудуть робити.


Яка різниця між %gі %G?
янпас

@yanpas, малі / великі регістри символу експонента відповідно.
Фредерік Хаміді

вибачте,% g і% G роблять вихідний символ E. Також вони виводять INF та inf у різних випадках
yanpas
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.