c++ printf size-t

Limpiar código para imprimir f size_t en C++(o: El equivalente más cercano de% z de C99 en C++)



printf size-t (8)

El especificador de formato printf %zu funcionará bien en sistemas C ++; no hay necesidad de hacerlo más complicado.

Tengo un código C ++ que imprime un size_t :

size_t a; printf("%lu", a);

Me gustaría que esto se compile sin advertencias en las arquitecturas de 32 y 64 bits.

Si esto fuera C99, podría usar printf("%z", a); . Pero AFAICT %z no existe en ningún dialecto estándar de C ++. Entonces, en cambio, tengo que hacer

printf("%lu", (unsigned long) a);

que es realmente feo

Si no hay ninguna posibilidad para imprimir size_t s integrado en el lenguaje, me pregunto si es posible escribir un contenedor printf o algo así que inserte los cambios adecuados en size_t s para eliminar las advertencias falsas del compilador y al mismo tiempo mantener las buenas.

¿Algunas ideas?

Editar Para aclarar por qué estoy usando printf: Tengo una base de código relativamente grande que estoy limpiando. Utiliza wrappers de impresión para hacer cosas como "escribir una advertencia, registrarla en un archivo y posiblemente salir del código con un error". Podría ser capaz de reunir suficientes C ++ - foo para hacer esto con un contenedor de cout, pero preferiría no cambiar todas las llamadas warn () en el programa solo para deshacerse de algunas advertencias del compilador.

El tipo efectivo subyacente size_t depende de la implementación . C Standard lo define como el tipo devuelto por el operador sizeof; además de ser unsigned y una especie de tipo integral, el size_t puede ser prácticamente cualquier cosa que tenga el tamaño más grande que se espera que sea devuelto por sizeof ().

En consecuencia, la cadena de formato que se utilizará para un tamaño_t puede variar según el servidor. Siempre debe tener la "u", pero puede ser I o D o tal vez algo más ...

Un truco podría ser convertirlo al tipo integral más grande en la máquina, asegurando que no haya pérdidas en la conversión, y luego usar la cadena de formato asociada con este tipo conocido.


En Windows y la implementación de Visual Studio de printf

%Iu

funciona para mi. ver msdn


La biblioteca de formato C ++ proporciona una implementación portátil rápida (y segura) de printf incluido el modificador z para size_t :

#include "format.h" size_t a = 42; int main() { fmt::printf("%zu", a); }

Además de eso, es compatible con la sintaxis de cadenas de formato similar a Python y captura información de tipo para que no tenga que proporcionarla manualmente:

fmt::print("{}", a);

Ha sido probado con los principales compiladores y proporciona resultados consistentes en todas las plataformas.

Descargo de responsabilidad : soy el autor de esta biblioteca.


La mayoría de los compiladores tienen su propio especificador para los argumentos size_t y ptrdiff_t , Visual C ++, por ejemplo, usa% Iu y% Id respectivamente, creo que gcc te permitirá usar% zu y% zd.

Podrías crear una macro:

#if defined(_MSC_VER) || defined(__MINGW32__) //__MINGW32__ should goes before __GNUC__ #define JL_SIZE_T_SPECIFIER "%Iu" #define JL_SSIZE_T_SPECIFIER "%Id" #define JL_PTRDIFF_T_SPECIFIER "%Id" #elif defined(__GNUC__) #define JL_SIZE_T_SPECIFIER "%zu" #define JL_SSIZE_T_SPECIFIER "%zd" #define JL_PTRDIFF_T_SPECIFIER "%zd" #else // TODO figure out which to use. #if NUMBITS == 32 #define JL_SIZE_T_SPECIFIER something_unsigned #define JL_SSIZE_T_SPECIFIER something_signed #define JL_PTRDIFF_T_SPECIFIER something_signed #else #define JL_SIZE_T_SPECIFIER something_bigger_unsigned #define JL_SSIZE_T_SPECIFIER something_bigger_signed #define JL_PTRDIFF_T_SPECIFIER something-bigger_signed #endif #endif

Uso:

size_t a; printf(JL_SIZE_T_SPECIFIER, a); printf("The size of a is " JL_SIZE_T_SPECIFIER " bytes", a);


Ya que estás usando C ++, ¿por qué no usar IOStreams? Eso debería compilarse sin advertencias y hacer lo correcto, siempre que no esté usando una implementación de C ++ con muerte cerebral que no define a un operator << para size_t .

Cuando la salida real tiene que hacerse con printf() , puede combinarla con IOStreams para obtener un comportamiento seguro para el tipo:

size_t foo = bar; ostringstream os; os << foo; printf("%s", os.str().c_str());

No es súper eficiente, pero su caso anterior trata con E / S de archivos, así que ese es su cuello de botella, no este código de formato de cadena.


aquí hay una posible solución, pero no es tan bonita ...

template< class T > struct GetPrintfID { static const char* id; }; template< class T > const char* GetPrintfID< T >::id = "%u"; template<> struct GetPrintfID< unsigned long long > //or whatever the 64bit unsigned is called.. { static const char* id; }; const char* GetPrintfID< unsigned long long >::id = "%lu"; //should be repeated for any type size_t can ever have printf( GetPrintfID< size_t >::id, sizeof( x ) );


C ++ 11

C ++ 11 importa C99, por lo que std::printf debería ser compatible con el especificador de formato C99 %zu .

C ++ 98

En la mayoría de las plataformas, size_t y uintptr_t son equivalentes, en cuyo caso puede usar la macro PRIuPTR definida en <cinttypes> :

size_t a = 42; printf("If the answer is %" PRIuPTR " then what is the question?/n", a);

Si realmente quiere estar seguro, uintmax_t a uintmax_t y use PRIuMAX :

printf("If the answer is %" PRIuMAX " then what is the question?/n", static_cast<uintmax_t>(a));