PRINTF(3)

NOME
printf, fprintf, sprintf, snprintf, vprintf, vfprintf, vsprintf, vsnprintf - conversão de saída formatada

SINÓPSE
#include <stdio.h>

int printf(const char *formato, ...);
int fprintf(FILE *fluxo, const char *formato, ...);
int sprintf(char *str, const char *formato, ...);
int snprintf(char *str, size_t size, const char *formato, ...);

#include <stdarg.h>

int vprintf(const char *formato, va_list ap);
int vfprintf(FILE *fluxo, const char *formato, va_list ap);
int vsprintf(char *str, const char *formato, va_list ap);
int vsnprintf(char *str, size_t size, const char *formato, va_list ap);

DESCRIÇÃO
As funções na família printf produzem saída de acordo com um formato como descrito abaixo. As funções printf e vprintf escrevem saída para stdout, o fluxo de saída padrão; fprintf e vfprintf escrevem para o dado fluxo de saída; sprintf, snprintf, vsprintf e vsnprintf escrevem para a seqüencia de caracteres str.

As funções vprintf, vfprintf, vsprintf e vsnprintf são equivalentes às funções printf, fprintf, sprintf e snprintf, respectivamente, exceto que elas são chamadas com uma va_list em vez de um número de argumentos variável. Essas funções não chamam a macro va_end. Conseqüentemente, o valor de ap é indefinido após a chamada. A aplicação deve chamar va_end(ap) posteriormente.

Estas oito funções escrevem a saída sob o controle de uma seqüencia de formato que especifica como os argumentos subseqüentes (ou os argumentos acessados via as facilidades de argumento de comprimento variável de stdarg(3)) são convertidos para a saída.

  Valor de Retorno
Estas funções retornam o número de caracteres impressos (não incluindo o `\0' terminador utilizado para finalizar a saída para seqüencias). snprintf e vsnprintf não escrevem mais do que tamanho bytes (incluindo o '\0' terminador), e retornam -1 se a saída foi truncada devido a esse limite. (Assim até a glibc 2.0.6. A partir da glibc 2.1 estas funções seguem o padrão C99 e retornam o número de caracteres (excluindo o '\0' terminador) que teriam sido escritos para a seqüencia final se espaço suficiente estivesse disponível.)

  Formato da seqüencia de formato
A seqüencia de formato é uma seqüencia de caracteres, começando e terminando em seu estado de transição inicial, se existir. A seqüencia de formato é composta de zero ou mais diretivas: caracteres comuns (não %), que são copiados sem alteração para o fluxo de saída; e especificações de conversão, cada uma das quais resulta em buscar zero ou mais argumentos subseqüentes. Cada especificação de conversão é introduzida pelo caractere %, e acaba com um especificador de conversão. No meio disso pode haver (nesta ordem) zero ou mais sinalizadores, uma largura de campo mínima opcional, uma precisão opcional e um modificador de comprimentoopcional. Os argumentos devem corresponder adequadamente (após promoção de tipo) ao especificador de conversão. Por padrão, os argumentos são utilizados na ordem dada, onde cada '*' e cada especificador de conversão pede pelo próximo argumento (e é um erro se argumentos insuficientes são fornecidos). Pode-se também especificar explicitamente qual argumento é tomado, em cada lugar em que um argumento é necessário, escrevendo-se '%m$' em vez de '%' e '*m$' em vez de '*', onde o inteiro decimal m denota a posição na lista de argumentos do argumento desejado, indexada a partir de 1. Assim,
    	printf("%*d", largura, num);
e
    	printf("%2$*1$d", largura, num);
são equivalentes. O segundo estilo permite repetidas referências ao mesmo argumento. O padrão C99 não inclui o estilo utilizando '$', que vem da Single Unix Specification. Se o estilo utilizando argumento e todos os argumentos de largura e precisão, mas ela pode ser misturada com formatos '%%' que não consomem um argumento. Não deve haver lacunas entre os números de argumentos especificados utilizando-se '$'; por exemplo, se os argumentos 1 e 3 são especificados, o argumento 2 deve ser especificado também em algum lugar na seqüencia de formato. Para algumas conversões numéricas, um caractere de base ('ponto decimal') ou um caractere de agrupamento de milhar é utilizado. O verdadeiro caractere utilizado depende do componente LC_NUMERIC da localização. A localização POSIX utiliza '.' como caractere de base, e não possui um caractere de agrupamento. Assim,
    	printf("%'.2f", 1234567.89);
resulta em '1234567.89' na localização POSIX, em '1234567,89' na localização nl_NL e em '1.234.567,89' na localização da_DK.

  Os caracteres sinalizadores
O caractere % é seguido por zero ou mais dos seguintes sinalizadores:

#   O valor deve ser convertido para uma 'forma alternativa'. Para conversões o, o primeiro caractere da seqüencia de saída é tornado zero (prefixando um 0 se ele ainda não era zero). Para conversões x e X, um resultado não-zero tem a seqüencia '0x' (ou '0X' para conversões X) adicionada ao seu início. Para conversões a, A, e, E, f, F, g, e G, o resultado conterá sempre um ponto decimal, mesmo se nenhum dígito o segue (normalmente, um ponto decimal aparece nos resultados daquelas conversões apenas se um dígito o seguir). Para conversões g e G, zeros não-significativos não são removidos do resultado, como seriam em outro caso. Para outras conversões, o resultado é indefinido.

0   O valor deve ser preenchido com zeros. Para conversões d, i, o, u, x, X, a, A, e, E, f, F, g, e G, o valor convertido é preenchido à esquerda com zeros em vez de espaço em branco. Se ambos os sinalizadores 0 e - aparecem, o sinalizador 0 é ignorado. Se uma precisão é fornecida com uma conversão numérica (d, i, o, u, x, e X), o sinalizador 0 é ignorado. Para outras conversões, o comportamento é indefinido.

-   O valor convertido deve ser ajustado à esquerda nos limites do campo. (O padrão é justificação à direita.) Exceto para conversões n, o valor convertido é preenchido na direita com espaço em branco, em vez de na esqerda com brancos ou zeros. Um - sobrepõe um 0 se ambos forem fornecidos.

' ' (um espaço) Um branco deve ser deixado antes de um número positivo (ou seqüencia vazia) produzido por uma conversão com sinal.

+   Um sinal (+ or -) sempre deve ser colocado antes de um número produzido por uma conversão com sinal. Por padrão, um sinal é utilizado apenas para números negativos. Um + sobrepõe um espaço se ambos forem utilizados.

Os cinco caracteres sinalizadores acima são definidos no padrão C. O SUSv2 especifica um caractere sinalizador adicional.

'   Para conversão decimal (i, d, u, f, F, g, G), a saída deve ser agrupada com caracteres de agrupamento de milhar se a informação de localização indicar algum. Note que muitas versões do gcc não podem analisar essa opção e emitirão um aviso. O SUSv2 não inclui %'F.

A glibc 2.2 adiciona mais um caractere sinalizador.

I   Para conversão inteira decimal (i, d, u), a saída utiliza os dígitos de saída alternativos da localização, se existirem (por exemplo, dígitos Arábicos). Entretanto, ela não inclui quaisquer definições de localização com tais dígitos definidos.

  A largura do campo
Uma seqüencia opcional de dígitos decimais (com o primeiro dígito não-zero) especificando uma largura mínima de campo. Se o valor convertido tem menos caracteres que a largura do campo, ele será preenchido com espaços à esquerda (ou direita, se o sinalizador de ajuste à esquerda tiver sido dado). Em vez de uma seqüencia de dígitos decimais, pode-se escrever '*' ou '*m$' (para algum inteiro decimal m) para especificar que a largura do campo é fornecida no próximo argumento, ou no m-ésimo argumento, respectivamente, que deve ser do tipo int. Uma largura de campo negativa é tomada como um sinalizador '-' seguido por uma largura de campo positiva. Em nenhum caso uma largura de campo não-existente ou pequena causará truncamento de um campo; se o resultado de uma conversão for maior que a largura do campo, o campo será expandido para conter o resultado da conversão.

  A precisão
Uma precisão opcional, na forma de um ponto ('.') seguido por uma seqüencia opcional de dígitos decimais. Em vez de uma seqüencia de dígitos decimais, pode-se escrever '*' ou '*m$' (para algum inteiro decimal m) para especificar que a precisão é fornecida no próximo argumento, ou no m-ésimo argumento, respectivamente, que deve ser do tipo int. Se a precisão for dada apenas como '.', ou se for negativa, ela é tomada como zero. Isso fornece o número mínimo de dígitos para aparecer em conversões d, i, o, u, x e X, o número de dígitos para aparecer depois do caractere de base em conversões a, A, e, E, f e F, o número máximo de dígitos significativos em conversões g e G, ou o número máximo de caracteres a serem impressos de uma seqüencia em conversões s e S.

  O modificador de comprimento
Aqui, 'conversão de inteiro' significa conversão d, i, o, u, x ou X.

hh  Uma conversão de inteiro em seguida corresponde a um argumento signed char ou unsigned char, ou uma conversão n em seguida corresponde a um ponteiro para um argumento signed char.

h   Uma conversão de inteiro em seguida corresponde a um argumento short int ou unsigned short int, ou uma conversão n em seguida corresponde a um ponteiro para um argumento short int.

l   (éle) Uma conversão de inteiro em seguida corresponde a um argumento long int ou unsigned long int, ou uma conversão n em seguida corresponde a um ponteiro para um argumento long int, ou uma conversão c em seguida corresponde a um argumento wint_t, ou uma conversão s em seguida corresponde a um ponteiro para um argumento wchar_t.

ll  (éle-éle). Uma conversão de inteiro em seguida corresponde a um argumento long long int ou unsigned long long int, ou uma conversão n em seguida corresponde a um ponteiro para um argumento long long int.

L   Uma conversão a, A, e, E, f, F, g ou G corresponde a um argumento long double. (O C99 permite %LF, mas o SUSv2 não.)

q   ('quad'. Apenas BSD 4.4 e Linux libc5. Não utilize.) Isso é um sinônimo para ll.

j   Uma conversão de inteiro em seguida corresponde a um argumento intmax_t ou uintmax_t.

z   Uma conversão de inteiro em seguida corresponde a um argumento size_t ou ssize_t. (Linux libc5 tem Z com esse significado. Não o utilize.)

t   Uma conversão de inteiro em seguida corresponde a um argumento ptrdiff_t.

O SUSv2 reconhece apenas os modificadores de comprimento h (em hd, hi, ho, hx, hX, hn), l (em ld, li, lo, lx, lX, ln, lc, ls) e L (em Le, LE, Lf, Lg, LG).

  O especificador de conversão
Um caractere que especifica o tipo de conversão a ser aplicado. Os especificadores de conversão e seus significados são:

d,i O argumento int é convertido para notação decimal com sinal. A precisão, se houver, fornece o mínimo número de dígitos que devem aparecer; se o valor convertido requiser menos dígitos, ele é preenchido à esquerda com zeros. A precisão padrão é 1. Quando 0 é exibido com uma precisão explícita de 0, a saída é vazia.

o,u,x,X
    O argumento unsigned int é convertido para notação octal sem sinal (o), decimal sem sinal (u), ou hexadecimal sem sinal (x e X). As letras abcdef são utilizadas para conversões x; as letras ABCDEF são utilizadas para conversões X. A precisão, se houver, fornece o número mínimo de dígitos que devem aparecer; se o valor convertido requiser menos dígitos, ele é preenchido à esquerda com zeros. A precisão padrão é 1. Quando 0 é exibido com uma precisão explícita de 0, a saída é vazia.

e,E O argumento double é arredondado e convertido no estilo [-]d.ddde\*(Pmdd onde há um dígito antes do caractere de ponto decimal e o número de dígitos após ele é igual à precisão; se a precisão estiver faltando, ela é tomada como 6; se a precisão for zero, o caractere de ponto decimal não aparece. Uma conversão E utiliza a letra E (em vez de e) para introduzir o expoente. O expoente sempre contém pelo menos dois dígitos; se o valor for zero, o expoente é 00.

f,F O argumento double é arredondado e convertido para notação decimal no estilo [-]ddd.ddd, onde o número de dígitos após o caractere de ponto decimal é igual à especificação de precisão. Se a precisão estiver faltando, ela é tomada como 6; se a precisão for explicitamente zero, o caractere de ponto decimal não aparece. Se um ponto decimal aparecer, pelo menos um dígito aparece antes dele. (O SUSv2 não reconhece F e diz que representações de seqüencia de caracteres para infinidade e NaN ("Not a Number" - Não é Número) podem ser tornadas disponíveis. O padrão C99 especifica '[-]inf' ou '[-]infinity' para infinidade, e uma seqüencia começando com 'nan' para NaN, no caso de conversão f, e '[-]INF' ou '[-]INFINITY' ou 'NAN*' no caso de conversão F.)

g,G O argumento double é convertido no estilo f ou e (ou F ou E para conversões G). A precisão especifica o número de dígitos significativos. Se a precisão estiver faltando, 6 dígitos são fornecidos; se a precisão for zero, ela é tratada como 1. O estilo e é utilizado se o expoente de sua conversão é menor que -4 ou maior que ou igual à precisão. Zeros não-significativos são removidos da parte fracional do resultado; um ponto decimal aparece apenas se ele for seguido por pelo menos um dígito.

a,A (C99; não em SUSv2) Para conversão a, o argumento double é convertido para notação hexadecimal (utilizando as letras abcdef) no estilo [-]0xh.hhhhp\*(Pmd; para conversão A, o prefixo 0X, as letras ABCDEF, e o separador de expoente P são utilizados. Há um dígito hexadecimal antes do ponto decimal, e o número de dígitos após ele é igual à precisão. A precisão padrão é suficiente para uma representação exata do valor se uma representação exata em base 2 existir e, caso contrário, é suficientemente grande para distingüir valores de tipo double. O dígito antes do ponto decimal é inespecificado para números não-normalizados e não-zero, mas de outra forma inespecificado, para números normalizados.

c   Se não houver modificador l presente, o argumento int é convertido para um unsigned char, e o caractere resultante é escrito. Se um modificador l estiver presente, o argumento wint_t (caractere largo) é convertido para uma seqüência multibyte por uma chamada à função wcrtomb, com um estado de conversão começando no estado inicial e a seqüencia multibyte resultante é escrita.

s   Se não houver modificador l presente: espera-se que o argumento const char * seja um ponteiro para um vetor de tipo caractere (ponteiro para uma seqüencia). Caracteres do vetor são escritos até (mas não incluindo) um caractere NULO terminador; se uma precisão for especificada, não mais que o número especificado é escrito. Se uma precisão for dada, não é necessário um caractere nulo presente; se a precisão não for especificada, ou se for maior que o tamanho do vetor, o vetor deve conter um caractere NULO terminador. Se um modificador l estiver presente: espera-se que o argumento const wchar_t * seja um ponteiro para um vetor de caracteres largos. Os caracteres largos do vetor são convertidos para caracteres multibyte (cada um por uma chamada à função wcrtomb, com um estado de conversão começando no estado inicial antes do primeiro caractere largo), até e incluindo um caractere largo nulo terminador. Os caracteres multibyte resultantes são escritos até (mas não incluindo) o byte nulo terminador. Se uma precisão for especificada, não mais que o número especificado de bytes são escritos, mas nenhum caractere multibyte parcial é escrito. Note que a precisão determina o número de bytes escritos, não o número de caracteres largos ou posições de tela. O vetor deve conter um caractere largo nulo de terminação, a menos que uma precisão seja fornecida e ela seja tão pequena que o número de bytes escritos a exceda antes que o fim do vetor seja atingido.

C   (Não em C99, mas em SUSv2.) Sinônimo para lc. Não utilize.

S   (Não em C99, mas em SUSv2.) Sinônimo para ls. Não utilize.

p   O argumento de ponteiro void * é exibido em hexadecimal (como se por %#x ou %#lx).

n   O número de caracteres escritos até o momento é armazenado no inteiro indicado pelo argumento de ponteiro int * (ou variante). Nenhum argumento é convertido.

%   Um '%' é escrito. Nenhum argumento é convertido. A especificação de conversão completa é '%%'.

EXEMPLOS
Para exibir até 5 casas decimais:
    #include <math.h>
    #include <stdio.h>
    fprintf(stdout, "pi = %.5f\n", 4 * atan(1.0));

Para exibir uma data e hora na forma 'Sunday, July 3, 10:02', onde weekday e month são ponteiros para seqüencias:
    #include <stdio.h>
    fprintf(stdout, "%s, %s %d, %.2d:%.2d\n",
    	weekday, month, day, hour, min);

Muitos países utilizam a ordem dia-mês-ano. Portanto, uma versão internacionalizada deve estar apta a exibir os argumentos em uma ordem especificada pelo formato:
    #include <stdio.h>
    fprintf(stdout, format,
    	weekday, month, day, hour, min);
onde format depende da localização, e poderia permutar os argumentos. Com o valor
    "%1$s, %3$d. %2$s, %4$d:%5$.2d\n"
pode-se obter 'Sonntag, 3. Juli, 10:02'.

Para alocar uma seqüencia suficientemente grande e nela imprimir (código correto para ambas glibc 2.0 e glibc 2.1):
    #include <stdio.h>
    #include <stdlib.h>
    #include <stdarg.h>
    char *
    make_message(const char *fmt, ...) {
       /* Adivinha que não precisamos de mais de 100 bytes. */
       int n, size = 100;
       char *p;
       va_list ap;
       if ((p = malloc (size)) == NULL)
          return NULL;
       while (1) {
          /* Tenta imprimir no espaço alocado. */
          va_start(ap, fmt);
          n = vsnprintf (p, size, fmt, ap);
          va_end(ap);
          /* Se aquilo funcionou, retorna a string. */
          if (n > -1 && n < size)
             return p;
          /* Caso contrário, tenta novamente com mais espaço. */
          if (n > -1)    /* glibc 2.1 */
             size = n+1; /* precisamente o que é necessário */
          else           /* glibc 2.0 */
             size *= 2;  /* duas vezes o tamanho anterior */
          if ((p = realloc (p, size)) == NULL)
             return NULL;
       }
    }

VEJA TAMBÉM
printf(1), wcrtomb(3), wprintf(3), scanf(3), locale(5).

DE ACORDO COM
As funções fprintf, printf, sprintf, vprintf, vfprintf e vsprintf estão de acordo com ANSI X3.159-1989 ('ANSI C') e ISO/IEC 9899:1999 ('ISO C99'). As funções snprintf e vsnprintf estão de acordo com ISO/IEC 9899:1999.

Em relação ao valor de retorno de snprintf, os padrões SUSv2 e C99 contradizem um ao outro: quando snprintf é chamada com tamanho=0, então o SUSv2 estipula um valor de retorno inespecificado menor que 1, enquanto o C99 permite que str seja NULO nesse caso e fornece o valor de retorno (como sempre) como o número de caracteres que teriam sido escritos caso a seqüencia de saída fosse grande o suficiente.

A libc4 Linux reconhece os cinco sinalizadores padrão do C. Ela reconhece os modificadores de comprimento h, l, L e as conversões cdeEfFgGinopsuxX, onde F é um sinônimo para f. Adicionalmente, ela aceita D, O e U como sinônimos para ld, lo e lu. (Isso é ruim e causou bugs sérios mais tarde, quando o suporte para %D desapareceu.) Não há caractere de base dependente de localização, separador de milhar, NaN ou infinidade, nem %m$ e *m$.

A libc5 Linux reconhece os cinco sinalizadores padrão do C e o sinalizador ', localização, %m$ e *m$. Ela reconhece os modificadores de comprimento h, l, L, Z e q, mas aceita ambos L e q para "long doubles" e para "long long integers" (isso é um bug). Ela não reconhece mais FDOU, mas adiciona um novo caractere de conversão m, que emite strerror(errno).

A glibc 2.0 adiciona os caracteres de conversão C e S.

A glibc 2.1 adiciona os modificadores de comprimento hh, j, t, z e os caracteres de conversão a e A.

A glibc 2.2 adiciona o caractere de conversão F com a semântica do C99, e o caractere sinalizador I.

HISTÓRIA
O Unix V7 define as três rotinas printf, fprintf, sprintf e possui o sinalizador -, a largura ou precisão *, o modificador de comprimento l, e as conversões doxfegcsu, e também D, O, U e X como sinônimos para ld, lo, lu e lx. Isso ainda é verdade para o BSD 2.9.1, mas o BSD 2.10 possui os sinalizadores #, + e <espaço> e não menciona mais D, O, U e X. O BSD 2.11 possui vprintf, vfprintf, vsprintf e avisa para não utilizar D, O, U e X. O BSD 4.3 Reno possui o sinalizador 0, os modificadores de comprimento h e L e as conversões n, p, E, G e X (com o significado atual) e deprecia D, O e U. O BSD 4.4 introduz as funções snprintf e vsnprintf e o modificador de comprimento q. O FreeBSD também possui funções asprintf e vasprintf, que alocam um buffer grande o suficiente para sprintf.

PROBLEMAS
Devido a sprintf e vsprintf assumirem uma seqüencia arbitrariamente longa, os chamadores devem ter cuidado de não exceder o espaço verdadeiro; isso é geralmente impossível de garantir. Note que o comprimento das seqüencias produzidas é dependente de localização e difícil de prever. Utilize snprintf e vsnprintf ao invés (ou asprintf e vasprintf).

A libc4.[45] Linux não possui uma snprintf, mas fornece uma libbsd que contém uma snprintf equivalente à sprintf, isto é, uma que ignora o argumento tamanho. Desse modo, o uso de snprintf com libc4 antigas leva a sérios problemas de segurança.

Código como printf(foo); geralmente indica um bug, uma vez que foo pode conter um caractere %. Se foo é proveniente de entrada não-confiável de usuário, ele pode conter %n, fazendo a chamada a printf escrever em memória e criando um furo de segurança.

Algumas conversões de ponto flutuante sob antigas libc4 causavam perdas ('leaks') de memória.

TRADUZIDO POR LDP-BR em 30/07/2001.

  Tradução:
Marcelo M. de Abreu <mmabreu@terra.com.br>

  Revisão.:
Marcelo Pereira da Silva <marcelo@pereira.com>