¿Cómo formatea un int largo sin signo con 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;
}

Salida:

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

Supongo que este resultado inesperado es de imprimir el unsigned long long int. ¿Cómo hacer que printf()una unsigned long long int?

andrewrk
fuente
2
Acabo de compilar su código (con% llu) con gcc y la salida fue la correcta. ¿Estás pasando alguna opción al compilador?
Juan
2
Tenga en cuenta que newlib de samsung bada parece no admitir "% lld": developer.bada.com/forum/…
RzR
Sugeriría usar stdint.h y ser explícito sobre el número de bits en su variable. Todavía estamos en un período de transición entre arquitecturas de 32 y 64 bits, y "unsigned long long int" no significa lo mismo en ambos.
BD en Rivenhill

Respuestas:

483

Use el modificador ll (el-el) long-long con la conversión u (sin signo). (Funciona en windows, GNU).

printf("%llu", 285212672);
John Downey
fuente
11
O para ser precisos, es para GNU libc, y no funciona con el tiempo de ejecución C de Microsoft.
Mark Baker,
168
Esto no es una cosa de Linux / UNIX, el modificador de longitud "ll" se agregó al Estándar C en C99, si no funciona en "Microsoft C" es porque no cumplen con los estándares.
Robert Gamble
12
Funciona para mí en VS2008. Además, por lo que recuerdo, el compilador MS C (cuando está configurado para compilar C directo) se supone que cumple con C90 por diseño; C99 introdujo algunas cosas que no a todos les gustaban.
ス ー パ ー フ ァ ミ コ ン
66
Una cosa a tener en cuenta aquí es que si está pasando múltiples long longargumentos printfy usa el formato incorrecto para uno de ellos, digamos en %dlugar de %lld, entonces incluso los argumentos impresos después del incorrecto pueden estar completamente desactivados (o incluso pueden provocar printfun bloqueo ) Esencialmente, los argumentos variables se pasan a printf sin ningún tipo de información, por lo que si la cadena de formato es incorrecta, el resultado es impredecible.
dmitrii
1
Escuché a Herb Sutter decir en una entrevista que los clientes de Microsoft no piden C99, por lo que su compilador de C puro se ha congelado en C90. Eso se aplica si está compilando como C. Si compila como C ++, como otros han señalado anteriormente, debería estar bien.
ahcox
90

Es posible que desee probar el uso de la biblioteca inttypes.h que proporciona tipos, tales como int32_t, int64_t, uint64_tetc. A continuación, puede utilizar sus macros, tales como:

uint64_t x;
uint32_t y;

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

Esto está "garantizado" para no darle el mismo problema long, unsigned long longetc., ya que no tiene que adivinar cuántos bits hay en cada tipo de datos.

Nathan Fellman
fuente
donde estas PRId64, las PRId32macros definidas?
happy_marmoset
44
@happy_marmoset: se definen eninttypes.h
Nathan Fellman
44
Creo que necesitas PRIu64y PRIu32para enteros sin signo.
Lasse Kliemann
1
Es inttypes.hestándar? ¿No sería así stdint.h?
MD XF
2
Tenga en cuenta que estos tipos de ancho exacto son opcionales , ya que existen arquitecturas que no tienen tipos enteros de esos anchos exactos. Solo los tipos leastXy fastX(que en realidad pueden ser más anchos de lo indicado) son obligatorios.
DevSolar
78

%d-> para int

%u-> para unsigned int

%ld-> para long intolong

%lu-> para unsigned long into long unsigned intounsigned long

%lld-> para long long intolong long

%llu-> para unsigned long long intounsigned long long

Shivam Chauhan
fuente
¿Existe un especificador de formato como el número de dígitos para mostrar, justificación izquierda o derecha para% lld o% llu?
Asam Padeh
40

Por mucho tiempo (o __int64) usando MSVS, debe usar% I64d:

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

fuente
37

Esto se debe a que% llu no funciona correctamente en Windows y% d no puede manejar enteros de 64 bits. Sugiero usar PRIu64 en su lugar y también encontrará que es portátil para Linux.

Intenta esto en su lugar:

#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;
}

Salida

My number is 8 bytes wide and its value is 285212672. A normal number is 5.
Paul Hargreaves
fuente
+1 para la referencia a PRIu64, que nunca había visto, pero esto no parece portátil para Linux de 64 bits (al menos) porque PRIu64 se expande a "lu" en lugar de "llu".
BD en Rivenhill
8
¿Y por qué eso sería malo? Un valor largo es de 64 bits en Linux de 64 bits, como en cualquier otro sistema operativo, excepto en Windows.
Timbre
@BDatRivenhill Linux / Unix usa LP64 en el que largo es de 64 bits
phuclv
1
Sin embargo, para que sea más portátil, utilice int64_ten su lugar porque es muy posible que algunas implementaciones, con mucho, mucho más grande que la de largo
phuclv
Esto debería a la cima! - una pequeña actualización: error: sufijo no válido en literal; C ++ 11 requiere un espacio entre el literal y el identificador [-Wreserved-user-defined-literal]
tofutim
14

En Linux es %lluy en Windows es%I64u

Aunque he descubierto que no funciona en Windows 2000, ¡parece que hay un error allí!

Adam Pierce
fuente
con Windows, (o al menos, con el compilador de Microsoft C para Windows) también hay% I64d,% I32u y% I32d
JustJeff
1
¿Qué tiene que ver con Windows 2000? La biblioteca C es la que maneja printf.
CMircea
1
Justo lo que observé. Escribí una aplicación que usaba esta construcción y funcionaba perfectamente en WinXP pero escupía basura en Win2k. Tal vez sea algo relacionado con una llamada al sistema que la biblioteca C está haciendo al núcleo, tal vez sea algo relacionado con Unicode, quién sabe. Recuerdo tener que solucionarlo usando _i64tot () o algo así.
Adam Pierce
77
Parece que la EM ejerce nuevamente su "libertad para innovar" ... ;-)
Dronz
El problema de Win2k / Win9x probablemente se deba a que el unsigned long longtipo de datos es relativamente nuevo (en ese momento, con el estándar C99) pero los compiladores de C (incluido MinGW / GCC) utilizan el antiguo tiempo de ejecución de Microsoft C que solo admitía la especificación C89. Solo tengo acceso a documentos API de Windows realmente antiguos y razonablemente recientes. Por lo tanto, es difícil decir exactamente cuándo I64use dejó caer el soporte. Pero suena como la era XP.
veganaiZe
8

Compílelo como x64 con VS2005:

% llu funciona bien.

Arenoso
fuente
3

Además de lo que la gente escribió hace años:

  • Es posible que obtenga este error en gcc / mingw:

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

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

Entonces, su versión de mingw no está predeterminada en c99. Añadir esta bandera del compilador: -std=c99.

Bernd Elkemann
fuente
3

Aparentemente, a nadie se le ha ocurrido una solución multiplataforma * durante más de una década desde [el] año 2008, por lo que añadiré la mía 😛. Por favor vota. (Bromeando. No me importa)

Solución: lltoa()

Cómo utilizar:

#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));

Ejemplo de 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;
}

A diferencia de la %lldcadena de formato de impresión, esta funciona para mí con GCC de 32 bits en Windows.

*) Bueno, casi multiplataforma. En MSVC, aparentemente necesitas en _ui64toa()lugar de lltoa().

7vujy0f0hy
fuente
1
No tengo lltoa.
Antti Haapala
1

Las cosas no estándar son siempre extrañas :)

para la porción larga larga bajo GNU es L, lloq

y bajo ventanas creo que es llsolo

chispas
fuente
1

Maleficio:

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

Salida:

64bit: FFFFFFFFFFFFFFFF
lama12345
fuente
¡Muy agradable!
Me
Pero, casi todos los compiladores de C ++ y C dan la advertencia: advertencia: uso del modificador de longitud 'll' con el carácter de tipo 'p' [-Wformat =]
Seshadri R
2
Esta respuesta completamente rota tiene un comportamiento doblemente indefinido y ni siquiera comienza a responder la pregunta .
Antti Haapala
@AnttiHaapala Dices que esta respuesta está completamente rota con un comportamiento doblemente indefinido, ¿puedes explicarlo o debo eliminarlo? ¿O mantenerlo como un buen mal ejemplo?
lama12345
0

Bueno, una forma es compilarlo como x64 con VS2008

Esto funciona como cabría esperar:

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 el código de 32 bits, necesitamos usar el especificador de formato __int64 correcto% I64u. Así se hace.

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);

Este código funciona para el compilador VS de 32 y 64 bits.

vzczc
fuente
Pruebe con un número real de 64 bits en lugar de '285212672' y no creo que el primer ejemplo se ejecute correctamente, compilado en cualquier destino.
Dyasta