Especificador de formato correto para double in printf


482

Qual é o especificador de formato correto para doubleno printf? É %fou é %lf? Eu acredito que é %f, mas não tenho certeza.

Amostra de código

#include <stdio.h>

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

19
Se você está preso com uma biblioteca C89, "%lf"é indefinido; nas bibliotecas C99 e C11, é definido como o mesmo que "%f".
Pmg

1
Sua variante está a mais correta possível. %lfé o especificador de formato correto para double. Mas ficou assim em C99. Antes disso, era preciso usar %f.
AnT

Respostas:


626

"%f"é o (ou pelo menos um) formato correto para um duplo. Não é nenhum formato para um float, porque se você tentar passar um floatpara printf, vai ser promovido a doubleantes de printfrecebe-lo 1 . "%lf"também é aceitável sob o padrão atual - ele lé especificado como não tendo efeito se seguido pelo fespecificador de conversão (entre outros).

Observe que este é um local em que as printfstrings de formato diferem substancialmente das strings de formato scanf(e fscanfetc.). Para saída, você está transmitindo um valor , que será promovido de floatpara doublequando transmitido como um parâmetro variável. Para entrada, você está passando um ponteiro , que não é promovido; portanto, você precisa informar scanfse deseja ler um floatou a double, portanto scanf, %fsignifica que você deseja ler um floate %lfsignifica que você deseja ler um double(e, pelo que é vale a pena, para a long double, você usa %Lfpara printfou scanf).


1. C99, §6.5.2.2 / 6: "Se a expressão que denota a função chamada tiver um tipo que não inclua um protótipo, as promoções inteiras serão realizadas em cada argumento e os argumentos que possuem o tipo float serão promovidos para dobrar. Eles são chamados de promoções de argumento padrão ". Em C ++, o texto é um pouco diferente (por exemplo, não usa a palavra "protótipo"), mas o efeito é o mesmo: todos os parâmetros variáveis ​​sofrem promoções padrão antes de serem recebidos pela função.


8
Note que g++rejeita %lfao compilar com -Wall -Werror -pedantic:error: ISO C++ does not support the ‘%lf’ gnu_printf format
kynan

2
@ kynan: Se sim (pelo menos assumindo uma versão atual do g ++), isso é um bug no g ++. Para C89 / 90 e C ++ 98/03, permitir lera uma extensão. Os padrões C99 / 11 e C ++ 11 requerem a implementação para permitir isso.
Jerry Coffin

1
Curiosamente, scanf faz falta doubles representados por %lf: ele reclama que esperava float *e encontrou double *com apenas %f.
precisa

1
@JerryCoffin g ++ ainda o padrão é 98 g ++ modo
MM

5
@EricDand Isso porque scanfleva ponteiros para onde armazenar o que ele lê, então necessidades saber quão grande é o espaço que está sendo apontado pelo é, enquanto printfleva os próprios valores, e "promoções de argumento padrão" significam ambos acabam como doubles, de modo que o lé essencialmente opcional.
TripeHound 26/08/2015

63

Dado o padrão C99 (ou seja, o rascunho N1256 ), as regras dependem do tipo de função: fprintf (printf, sprintf, ...) ou scanf.

Aqui estão as partes relevantes extraídas:

Prefácio

Esta segunda edição cancela e substitui a primeira edição, ISO / IEC 9899: 1990, conforme alterada e corrigida pela ISO / IEC 9899 / COR1: 1994, ISO / IEC 9899 / AMD1: 1995 e ISO / IEC 9899 / COR2: 1996. As principais mudanças da edição anterior incluem:

  • %lf especificador de conversão permitido em printf

7.19.6.1 A fprintffunção

7 Os modificadores de comprimento e seus significados são:

l (ell) Especifica que (...) não tem efeito no seguinte especificador de conversão a, A, e, E, f, F, g ou G.

L Especifica que o seguinte especificador de conversão a, A, e, E, f, F, g ou G se aplica a um longo argumento duplo.

As mesmas regras especificadas para fprintfsolicitar printf, sprintfe funções similares.

7.19.6.2 A fscanffunção

11 Os modificadores de comprimento e seus significados são:

l (ell) Especifica que (...) o seguinte especificador de conversão a, A, e, E, f, F, g ou G se aplica a um argumento com o tipo ponteiro para duplo;

L Especifica que o seguinte especificador de conversão a, A, e, E, f, F, g ou G se aplica a um argumento com o ponteiro de tipo para long double.

12 Os especificadores de conversão e seus significados são: a, e, f, g Corresponde a um número de ponto flutuante opcionalmente assinado, (...)

14 Os especificadores de conversão A, E, F, G e X também são válidos e se comportam da mesma forma que, respectivamente, a, e, f, g e x.

A história longa, para fprintfos seguintes especificadores e tipos correspondentes são especificados:

  • %f -> duplo
  • %Lf -> long double.

e por fscanfisso é:

  • %f -> flutuar
  • %lf -> duplo
  • %Lf -> long double.

25

Pode ser %f, %gou %edependendo de como você deseja que o número seja formatado. Veja aqui para mais detalhes. O lmodificador é necessária scanfcom double, mas não em printf.


1
-1: o lmodificador (minúsculo) é para tipos inteiros ( cplusplus.com/reference/clibrary/cstdio/printf ) e Lpara tipos de ponto flutuante. Além disso, o Lmodificador espera a long double, não uma planície double.
user470379

10
user470379: Então, onde está a contradição com a minha resposta? Não vos disse que lnão é necessária printfpara double.
Vitaut

16

Formato %lfé um printfformato perfeitamente correto para double, exatamente como você o usou. Não há nada errado com o seu código.

O formato %lfin printfnão era suportado nas versões antigas (anteriores à C99) da linguagem C, que criavam "inconsistência" superficial entre os especificadores de formato para doublein printfe scanf. Essa inconsistência superficial foi corrigida em C99.

Você não é obrigado a usar %lfcom doubleno printf. Você também pode usar %f, se preferir ( %lfe %fé equivalente a printf). Mas no C moderno, faz todo o sentido preferir usar %fcom float, %lfcom doublee %Lfcom long double, consistentemente em ambos printfe scanf.


Com scanf(), "%f", "%lf"corresponder a um float *, double *, não float, doublecomo implica a última linha.
chux - Restabelece Monica

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.