Eu tenho uma variável do tipo size_t
e quero imprimi-la usando printf()
. Qual especificador de formato eu uso para imprimi-lo portably?
Na máquina de 32 bits, %u
parece certo. Eu compilei com g++ -g -W -Wall -Werror -ansi -pedantic
, e não houve aviso. Mas quando eu compilo esse código em uma máquina de 64 bits, ele produz um aviso.
size_t x = <something>;
printf("size = %u\n", x);
warning: format '%u' expects type 'unsigned int',
but argument 2 has type 'long unsigned int'
O aviso desaparece, como esperado, se eu mudar para %lu
.
A questão é: como posso escrever o código, para que ele seja compilado sem aviso em máquinas de 32 e 64 bits?
Edit: Como solução alternativa, acho que uma resposta pode ser "converter" a variável em um número inteiro que seja grande o suficiente, digamos unsigned long
, e imprima usando %lu
. Isso funcionaria nos dois casos. Estou procurando se há alguma outra idéia.
unsigned long
é a melhor opção se sua implementação da libc não suportar oz
modificador; o padrão C99 recomendasize_t
não ter um número inteiro de conversão classificação maior do quelong
, assim que você é razoavelmente seguroRespostas:
Use o
z
modificador:fonte
printf()
modificadores de comprimento do rascunho do C ++ 0x de 09/11/2009 (tabela 84 na página 672) #-pedantic
, precisará obter um compilador que suporte o rascunho C ++ 1x (altamente improvável) ou mover seu código para um arquivo compilado como C99. Caso contrário, sua única opção é converter suas variáveisunsigned long long
e usá%llu
-las para ser maximamente portátil.Parece que varia de acordo com o compilador que você está usando (blech):
%zu
(ou%zx
, ou%zd
mas que o exibe como se estivesse assinado, etc.)%Iu
(ou%Ix
,%Id
mas novamente assinou, etc.) - mas a partir da cl v19 (no Visual Studio 2015), a Microsoft oferece suporte%zu
(consulte esta resposta a este comentário )... e, claro, se você estiver usando C ++, poderá usar o
cout
que é sugerido pelo AraK .fonte
z
também é suportado por newlib (ie cygwin) #%zd
está incorreto parasize_t
; está correto para o tipo assinado correspondente asize_t
, mas emsize_t
si é um tipo não assinado.%zu
também (e%zx
no caso de eles quererem hex). É verdade que%zu
provavelmente deveria ter sido o primeiro da lista. Fixo.%zd
deveria estar na lista. Não consigo pensar em nenhum motivo para usar, em%zd
vez de%zu
imprimir umsize_t
valor. Nem é válido (tem comportamento indefinido) se o valor excederSIZE_MAX / 2
. (Para completar, você pode mencionar%zo
para octal.)ssize_t
seja o tipo assinado correspondentesize_t
, portanto, não é garantido que ele corresponda"%zd"
. ( Provavelmente está na maioria das implementações.) Pubs.opengroup.org/onlinepubs/9699919799/basedefs/…Para C89, use
%lu
e converta o valor paraunsigned long
:Para C99 e versões posteriores, use
%zu
:fonte
unsigned long long
?uint64_t
usar aPRIu64
macro de inttypes.h, que contém o especificador de formato.Ampliando a resposta de Adam Rosenfield para Windows.
Testei esse código nas versões VS2013 Update 4 e VS2015:
Saídas binárias geradas pelo VS2015:
enquanto o gerado pelo VS2013 diz:
Nota:
ssize_t
é uma extensão POSIX eSSIZE_T
é semelhante nos tipos de dados do Windows , portanto, adicionei<BaseTsd.h>
referência.Além disso, exceto os seguintes cabeçalhos C99 / C11, todos os cabeçalhos C99 estão disponíveis na visualização do VS2015:
Além disso, o C11
<uchar.h>
agora está incluído na última visualização.Para mais detalhes, consulte esta lista antiga e nova para conformidade padrão.
fonte
Para aqueles que falam sobre fazer isso em C ++, que não necessariamente suporta as extensões C99, recomendo vivamente o formato boost ::. Isso torna a questão size_t type size discutível:
Como você não precisa de especificadores de tamanho no formato boost ::, você pode se preocupar com como deseja exibir o valor.
fonte
%u
então.fonte
printf
especificador. Eu acho que eles têm algumas outras restrições não declaradas que tornam o uso destd::cout
um problema.printf
especificador ".fonte
Como AraK disse, a interface de fluxos c ++ sempre funcionará de maneira portável.
Se você deseja o C stdio, não há resposta portátil para isso em certos casos de "portable". E fica feio, pois, como você viu, escolher os sinalizadores de formato errado pode gerar um aviso do compilador ou gerar uma saída incorreta.
O C99 tentou resolver esse problema com formatos inttypes.h como "%" PRIdMAX "\ n". Mas, assim como em "% zu", nem todos são compatíveis com o c99 (como o MSVS anterior a 2013). Existem arquivos "msinttypes.h" flutuando para lidar com isso.
Se você converter para um tipo diferente, dependendo dos sinalizadores, poderá receber um aviso do compilador para truncamento ou alteração de sinal. Se você seguir esta rota, escolha um tipo de tamanho fixo relevante maior. Um de muito longo não assinado e "% llu" ou um longo "% lu" não assinado deve funcionar, mas o llu também pode desacelerar as coisas em um mundo de 32 bits como excessivamente grande. (Editar - meu mac emite um aviso em 64 bits para% llu que não corresponde a size_t, mesmo que% lu,% llu e size_t sejam todos do mesmo tamanho. E% lu e% llu não são do mesmo tamanho no meu MSVS2012. pode ser necessário transmitir + usar um formato que corresponda.)
Nesse caso, você pode usar tipos de tamanho fixo, como int64_t. Mas espere! Agora voltamos ao c99 / c ++ 11, e o MSVS mais antigo falha novamente. Além disso, você também tem lançamentos (por exemplo, map.size () não é do tipo de tamanho fixo)!
Você pode usar um cabeçalho ou biblioteca de terceiros, como aumento. Se você ainda não estiver usando um, talvez não queira aumentar seu projeto dessa maneira. Se você deseja adicionar um apenas para esse problema, por que não usar fluxos c ++ ou compilação condicional?
Então, você deve usar fluxos c ++, compilação condicional, estruturas de terceiros ou algo portátil que funcione para você.
fonte
Será avisado se você passar um número inteiro não assinado de 32 bits para um formato% lu? Deve ser bom, pois a conversão é bem definida e não perde nenhuma informação.
Ouvi dizer que algumas plataformas definem macros em
<inttypes.h>
que você pode inserir na string de formato literal, mas não vejo esse cabeçalho no meu compilador Windows C ++, o que implica que pode não ser de plataforma cruzada.fonte
%lu
, deve converter osize_t
valor paraunsigned long
. Não há conversão implícita (além de promoções) para argumentos paraprintf
.C99 define "% zd" etc. para isso. (obrigado aos comentaristas) Não há um especificador de formato portátil para isso em C ++ - você pode usar
%p
qual palavra do woulkd nesses dois cenários, mas também não é uma opção portátil, e fornece o valor em hexadecimal.Como alternativa, use algum streaming (por exemplo, stringstream) ou uma substituição de impressão segura, como o Boost Format . Entendo que este conselho é apenas de uso limitado (e requer C ++). (Utilizamos uma abordagem semelhante adaptada às nossas necessidades ao implementar o suporte unicode.)
O problema fundamental para C é que printf usando reticências é inseguro por design - ele precisa determinar o tamanho do argumento adicional a partir dos argumentos conhecidos, portanto não pode ser corrigido para suportar "o que você obtiver". Portanto, a menos que seu compilador implemente algumas extensões proprietárias, você estará sem sorte.
fonte
z
modidfier tamanho é padrão C, mas algumas implementações libc está preso em 1990 por várias razões (por exemplo, Microsoft, basicamente abandonada C em favor do C ++ e - mais recentemente - C #)%zd
está errado, não está assinado, por isso deveria estar%zu
.Em algumas plataformas e para alguns tipos, existem especificadores específicos de conversão de impressão disponíveis, mas às vezes é preciso recorrer à conversão para tipos maiores.
Documentei esse problema complicado aqui, com o código de exemplo: http://www.pixelbeat.org/programming/gcc/int_types/ e atualizo-o periodicamente com informações sobre novas plataformas e tipos.
fonte
se você deseja imprimir o valor de size_t como uma string, você pode fazer isso:
O resultado é:
número: 2337200120702199116
texto: Vamos pescar em vez de sentar no nosso mas !!
Edit: relendo a questão por causa dos votos negativos, observei que o problema dele não é% llu ou% I64d, mas o tipo size_t em máquinas diferentes, consulte esta pergunta https://stackoverflow.com/a/918909/1755797
http: // www. cplusplus.com/reference/cstdio/printf/
size_t é int não assinado em uma máquina de 32 bits e não possui um longo e longo prazo em 64 bits,
mas% ll sempre espera um int longo e não assinado.
size_t varia em diferentes sistemas operacionais, enquanto% llu é o mesmo
fonte