especificadores de formato printf para uint32_t e size_t

101

Eu tenho o seguinte

size_t   i = 0;
uint32_t k = 0;

printf("i [ %lu ] k [ %u ]\n", i, k);

Recebo o seguinte aviso ao compilar:

format ‘%lu expects type long unsigned int’, but argument has type uint32_t

Quando fiz isso usando uma tala, obtive o seguinte:

Format argument 1 to printf (%u) expects unsigned int gets size_t: k

Muito obrigado por qualquer conselho,

ant2009
fonte
2
C89 não oferece suporte uint32_tde <stdint.h>ou <inttypes.h>; se você quiser usar esses tipos, deve atualizar para o C89. Como uma extensão, é provável que o GCC permita que você os use, mas o C89 não tinha esse suporte.
Jonathan Leffler
10
E o modificador de formato oficial C99 para size_té 'z', como em "%zu".
Jonathan Leffler
1
stackoverflow.com/questions/1401526/…
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
Acredito que a resposta de @kenny seja melhor para uint32_t, mas não existe size_t. A resposta de @ u0b34a0f6ae inclui ambos.
jww
A segunda menção de C89 no primeiro comentário de Jonathan Leffler deve ser C99
bph

Respostas:

28

Parece que você espera size_tser o mesmo que unsigned long(possivelmente 64 bits), quando na verdade é unsigned int(32 bits). Tente usar %zuem ambos os casos.

Não estou totalmente certo, porém.

Roda dentada
fonte
1
Sem avisos ao compilar. No entanto, executando o splint, obtenho o seguinte: 1) printf (% u) espera int não assinado obtém uint32_t: i 2) printf (% u) espera int não assinado obtém size_t: k
ant2009
Parece que a tala é apenas pedante, então. Provavelmente ele está mudando os nomes dos tipos no código-fonte e não percebe que são equivalentes. Eu me pergunto o que isso faria com a resposta de @ KennyTM ... Certamente deveria ser mais portátil.
Cogwheel
3
splint é realmente fazer a coisa certa. Só porque int32_testá intno seu compilador / plataforma, não significa que pode não estar longem outro. O mesmo para size_t. Ele está realmente saindo de seu caminho e fazendo mais trabalho para detectar esse bug de portabilidade, já que a verificação fácil e natural seria apenas honrar o typedef como o compilador faz.
R .. GitHub PARAR DE AJUDAR O ICE
4
-1, desculpe, não é portátil. Tudo o que é necessário é que os especificadores de formato e os tipos concordem, e você sempre pode lançar para tornar isso verdadeiro. long é de pelo menos 32 bits, então %lujunto com (unsigned long)kestá sempre correto. size_té mais complicado, por isso %zufoi adicionado no C99. Se você não pode usar isso, trate-o exatamente como k( longé o maior tipo no C89, size_té muito improvável que seja maior).
u0b34a0f6ae
139

Experimentar

#include <inttypes.h>
...

printf("i [ %zu ] k [ %"PRIu32" ]\n", i, k);

O zrepresenta um inteiro de comprimento igual a size_t, e a PRIu32macro, definida no cabeçalho C99inttypes.h , representa um inteiro não assinado de 32 bits.

Kennytm
fonte
3
@robUK: Heh. Eu sugiro que você registre um bug para a tala.
kennytm
8
Esta é a resposta certa. Embora minha recomendação pessoal seja simplesmente lançar, por exemplo printf( "%lu", (unsigned long )i ). Caso contrário, acabamos mais tarde com uma pilha de avisos em todo o código devido a uma mudança de tipo.
Dummy00001
1
Essa é a resposta correta. Eu concordo com o KennyTM sobre como preencher um bug para tala. A propósito, "% zu" é o formato adequado para size_t. Você não precisa de nenhuma das macros PRI * para imprimir size_t.
R .. GitHub PARAR DE AJUDAR O ICE
1
Se bem me lembro,% zu é C99, e na pergunta ele escreveu 'C89'.
Alcor
8
@alcor sim, ele colocou C89 (aparentemente o sinalizador do compilador gcc que ele está usando), mas ele está usando, uint32_tentão na verdade é o código C99 e deve ser compilado como tal.
Colin D Bennett
28

Tudo o que é necessário é que os especificadores de formato e os tipos concordem, e você sempre pode lançar para tornar isso verdadeiro. longtem pelo menos 32 bits, então %lujunto com (unsigned long)kestá sempre correto:

uint32_t k;
printf("%lu\n", (unsigned long)k);

size_té mais complicado, por isso %zufoi adicionado no C99. Se você não pode usar isso, trate-o exatamente como k( longé o maior tipo no C89, size_té muito improvável que seja maior).

size_t sz;
printf("%zu\n", sz);  /* C99 version */
printf("%lu\n", (unsigned long)sz);  /* common C89 version */

Se você não obtiver os especificadores de formato corretos para o tipo que está passando, printffará o equivalente a ler muita ou pouca memória do array. Contanto que você use casts explícitos para combinar tipos, é portátil.

u0b34a0f6ae
fonte
17

Se você não quiser usar as macros PRI *, outra abordagem para imprimir QUALQUER tipo inteiro é lançar em intmax_tou uintmax_te usar "%jd"ou %ju, respectivamente. Isso é especialmente útil para tipos de POSIX (ou outros sistemas operacionais) que não têm macros PRI * definidas, por exemplo off_t.

R .. GitHub PARAR DE AJUDAR O GELO
fonte