Como você formata um int longo e não assinado usando printf?

379
#include <stdio.h>
int main() {
    unsigned long long int num = 285212672; //FYI: fits in 29 bits
    int normalInt = 5;
    printf("My number is %d bytes wide and its value is %ul. A normal number is %d.\n", sizeof(num), num, normalInt);
    return 0;
}

Resultado:

My number is 8 bytes wide and its value is 285212672l. A normal number is 0.

Presumo que esse resultado inesperado seja da impressão do unsigned long long int. Como você printf()um unsigned long long int?

andrewrk
fonte
2
Acabei de compilar seu código (com% llu) com o gcc e a saída foi a correta. Você está passando alguma opção para o compilador?
Juan
2
Observe que o newlib do samsung bada parece não suportar "% lld": developer.bada.com/forum/…
RzR
Eu sugeriria o uso de stdint.he ser explícito sobre o número de bits na sua variável. Ainda estamos em um período de transição entre arquiteturas de 32 e 64 bits, e "unsigned long long int" não significa a mesma coisa para ambas.
BD em Rivenhill

Respostas:

483

Use o modificador ll (el-el) long-long com a conversão u (não assinada). (Funciona em janelas, GNU).

printf("%llu", 285212672);
John Downey
fonte
11
Ou, para ser mais preciso, é para GNU libc e não funciona com o tempo de execução C da Microsoft.
Mark Baker
168
Isso não é coisa do Linux / UNIX, o modificador de comprimento "ll" foi adicionado ao Standard C no C99, se não funcionar no "Microsoft C", é porque eles não são compatíveis com os padrões.
Robert Gamble
12
Funciona para mim no VS2008. Além disso, tanto quanto me lembro, o MS C Compiler (quando configurado para compilar diretamente C) deve ser compatível com C90 por design; O C99 introduziu algumas coisas que nem todos gostaram.
11119
6
Uma coisa a ter em mente aqui é que, se você estiver passando vários long longargumentos para printfe usar o formato errado para um deles, digamos, em %dvez de %lld, mesmo os argumentos impressos após o incorreto podem estar completamente desligados (ou até causar printfuma falha) ) Essencialmente, argumentos variáveis ​​são passados ​​para printf sem nenhuma informação de tipo; portanto, se a sequência de formatação estiver incorreta, o resultado será imprevisível.
dmitrii
11
Heard Herb Sutter disse em uma entrevista que os clientes da Microsoft não pedem C99, então seu compilador C puro foi congelado na C90. Isso se aplica se você estiver compilando como C. Se você compilar como C ++, como outros observaram acima, você deve estar bem.
ahcox
90

Você pode querer tentar usar a biblioteca inttypes.h que lhe dá tipos, tais como int32_t, int64_t, uint64_tetc. Você pode então usar suas macros, tais como:

uint64_t x;
uint32_t y;

printf("x: %"PRId64", y: %"PRId32"\n", x, y);

Isso é "garantido" para não causar o mesmo problema que long, unsigned long longetc, pois você não precisa adivinhar quantos bits existem em cada tipo de dados.

Nathan Fellman
fonte
onde estes PRId64, PRId32macros definidos?
happy_marmoset
4
@happy_marmoset: eles são definidos em #inttypes.h
Nathan Fellman /
4
Eu acho que você precisa PRIu64e PRIu32para números inteiros não assinados.
Lasse Kliemann
11
É inttypes.hpadrão? Não seria stdint.h?
MD XF
2
Observe que esses tipos de largura exata são opcionais , pois existem arquiteturas por aí que não possuem tipos inteiros dessas larguras exatas. Somente os tipos leastXe fastX(que podem realmente ser maiores que o indicado) são obrigatórios.
DevSolar
78

%d-> para int

%u-> para unsigned int

%ld-> para long intoulong

%lu-> para unsigned long intou long unsigned intouunsigned long

%lld-> para long long intoulong long

%llu-> para unsigned long long intouunsigned long long

Shivam Chauhan
fonte
Existe um especificador de formato como o número de dígitos a ser exibido, justificativa esquerda ou direita para% lld ou% llu?
Asam Padeh
40

Por muito tempo (ou __int64) usando MSVS, você deve usar% I64d:

__int64 a;
time_t b;
...
fprintf(outFile,"%I64d,%I64d\n",a,b);    //I is capital i

fonte
37

Isso ocorre porque% llu não funciona corretamente no Windows e% d não pode lidar com números inteiros de 64 bits. Eu sugiro usar o PRIu64 e você verá que também é portátil para Linux.

Tente isso:

#include <stdio.h>
#include <inttypes.h>

int main() {
    unsigned long long int num = 285212672; //FYI: fits in 29 bits
    int normalInt = 5;
    /* NOTE: PRIu64 is a preprocessor macro and thus should go outside the quoted string. */
    printf("My number is %d bytes wide and its value is %" PRIu64 ". A normal number is %d.\n", sizeof(num), num, normalInt);
    return 0;
}

Resultado

My number is 8 bytes wide and its value is 285212672. A normal number is 5.
Paul Hargreaves
fonte
+1 para a referência ao PRIu64, que eu nunca tinha visto, mas isso não parece portátil ao Linux de 64 bits (pelo menos) porque o PRIu64 se expande para "lu" em vez de "llu".
BD em Rivenhill
8
E por que isso seria ruim? Um comprimento é um valor de 64 bits no Linux de 64 bits, como em qualquer outro sistema operacional, exceto no Windows.
Ringding 4/03/12
@BDatRivenhill Linux / Unix utiliza LP64 em que longa tem 64 bits
phuclv
11
no entanto, para torná-lo mais portátil, use int64_tem vez disso, pois pode haver algumas implementações com muito maior que maior
phuclv
isso deve ao topo! - uma pequena atualização: erro: sufixo inválido no literal; C ++ 11 requer um espaço entre literal e identificador [-Wreserved-usuário definida-literal]
tofutim
14

No Linux é %llue no Windows é%I64u

Embora eu tenha achado que não funciona no Windows 2000, parece haver um bug por lá!

Adam Pierce
fonte
com janelas, (ou pelo menos, com o compilador C Microsoft para janelas) há também I64d%,% I32u, e% I32d
JustJeff
11
O que isso tem a ver com o Windows 2000? A biblioteca C é a que lida com printf.
CMircea
11
Apenas o que eu observei. Eu escrevi um aplicativo que usou essa construção e funcionou perfeitamente no WinXP, mas cuspiu lixo no Win2k. Talvez tenha algo a ver com uma chamada de sistema que a biblioteca C esteja fazendo no kernel, talvez tenha algo a ver com Unicode, quem sabe. Lembro-me de ter que contornar isso usando _i64tot () ou algo assim.
Adam Pierce
7
Soa como MS exercendo sua "liberdade para inovar" novamente ... ;-)
Dronz
O problema do Win2k / Win9x provavelmente se deve ao fato de o unsigned long longtipo de dados ser relativamente novo (na época, com o padrão C99), mas os compiladores C (incluindo MinGW / GCC) utilizando o antigo tempo de execução do Microsoft C, que suportava apenas a especificação C89. Eu só tenho acesso a documentos da API do Windows realmente antigos e razoavelmente recentes. Portanto, é difícil dizer exatamente quando o I64usuporte foi recebido. Mas parece a era XP.
veganaiZe
8

Compile-o como x64 com o VS2005:

% llu funciona bem.

Sandy
fonte
3

Além do que as pessoas escreveram anos atrás:

  • você pode receber este erro no gcc / mingw:

main.c:30:3: warning: unknown conversion type character 'l' in format [-Wformat=]

printf("%llu\n", k);

Então sua versão do mingw não é padronizada para c99. Adicionar esta bandeira compilador: -std=c99.

Bernd Elkemann
fonte
3

Aparentemente, ninguém inventou uma solução multiplataforma * por mais de uma década desde [o] ano de 2008, então acrescentarei a minha 😛. Voto positivo. (Brincadeira. Eu não ligo.)

Solução: lltoa()

Como usar:

#include <stdlib.h> /* lltoa() */
// ...
char dummy[255];
printf("Over 4 bytes: %s\n", lltoa(5555555555, dummy, 10));
printf("Another one: %s\n", lltoa(15555555555, dummy, 10));

Exemplo do OP:

#include <stdio.h>
#include <stdlib.h> /* lltoa() */

int main() {
    unsigned long long int num = 285212672; // fits in 29 bits
    char dummy[255];
    int normalInt = 5;
    printf("My number is %d bytes wide and its value is %s. "
        "A normal number is %d.\n", 
        sizeof(num), lltoa(num, dummy, 10), normalInt);
    return 0;
}

Ao contrário da %lldstring de formato de impressão, esta funciona para mim no GCC de 32 bits no Windows.

*) Bem, quase multiplataforma. No MSVC, você aparentemente precisa em _ui64toa()vez de lltoa().

7vujy0f0hy
fonte
11
Eu não tenho lltoa.
Antti Haapala
1

Coisas fora do padrão são sempre estranhas :)

para a longa porção longa sob GNU é L, llouq

e sob as janelas eu acredito que é llapenas

faíscas
fonte
1

Hex:

printf("64bit: %llp", 0xffffffffffffffff);

Resultado:

64bit: FFFFFFFFFFFFFFFF
lama12345
fonte
Muito agradável! eu queria saber como eu poderia obtê-lo em representação hexadecimal
0xAK
Porém, quase todos os compiladores C ++ e C emitem o aviso: warning: uso do modificador de comprimento 'll' com o caractere do tipo 'p' [-Wformat =]
Seshadri R
2
essa resposta totalmente quebrada tem um comportamento duplamente indefinido e nem sequer começa a responder à pergunta .
Antti Haapala
@AnttiHaapala Você diz que esta resposta é totalmente interrompida com um comportamento duplamente indefinido, você pode elaborar ou devo excluí-la? Ou mantê-lo como um bom exemplo ruim?
Lama12345
0

Bem, uma maneira é compilá-lo como x64 com o VS2008

Isso é executado conforme o esperado:

int normalInt = 5; 
unsigned long long int num=285212672;
printf(
    "My number is %d bytes wide and its value is %ul. 
    A normal number is %d \n", 
    sizeof(num), 
    num, 
    normalInt);

Para código de 32 bits, precisamos usar o especificador de formato __int64 correto% I64u. Assim se torna.

int normalInt = 5; 
unsigned __int64 num=285212672;
printf(
    "My number is %d bytes wide and its value is %I64u. 
    A normal number is %d", 
    sizeof(num),
    num, normalInt);

Esse código funciona para o compilador VS de 32 e 64 bits.

vzczc
fonte
Tente um número real de 64 bits em vez de '285212672' e não acredito que o primeiro exemplo seja executado corretamente, compilado em qualquer destino.
Dyasta 13/1018