Nettoyer le code à printf size_t en C ++ (ou: équivalent le plus proche de% z de C99 en C ++)

J’ai du code C ++ qui imprime une size_t :

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

Je voudrais que cela comstack sans avertissements sur les architectures 32 et 64 bits.

Si c’était C99, je pourrais utiliser printf("%z", a); . Mais AFAICT %z n’existe dans aucun dialecte C ++ standard. Donc, au lieu de cela, je dois faire

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

ce qui est vraiment moche.

S’il n’y a pas de possibilité d’imprimer size_t s intégré au langage, je me demande s’il est possible d’écrire un wrapper printf ou somesuch tel que cela insérera les casts appropriés sur size_t s afin d’éliminer les avertissements size_t compilateur tout en conservant les bons.

Des idées?


Modifier Pour clarifier pourquoi j’utilise printf: j’ai une base de code relativement grande que je nettoie. Il utilise des wrappers printf pour faire des choses comme “écrire un avertissement, le connecter à un fichier et éventuellement quitter le code avec une erreur”. Je pourrais peut – être rassembler suffisamment de C ++ – foo pour faire cela avec un wrapper cout, mais je préférerais ne pas changer tous les appels warn () du programme pour se débarrasser de certains avertissements du compilateur.

    La plupart des compilateurs ont leur propre spécificateur pour les arguments size_t et ptrdiff_t , Visual C ++ par exemple utilise respectivement% Iu et% Id, je pense que gcc vous permettra d’utiliser% zu et% zd.

    Vous pourriez créer une 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 

    Usage:

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

    Le printf format printf %zu fonctionnera correctement sur les systèmes C ++; il n’y a pas besoin de le rendre plus compliqué.

    Sur Windows et l’implémentation Visual Studio de printf

      %Iu 

    travaille pour moi. voir msdn

    C ++ 11

    C ++ 11 importe C99 afin que std::printf prenne en charge le spécificateur de format C99 %zu .

    C ++ 98

    Sur la plupart des plates-formes, size_t et uintptr_t sont équivalents, auquel cas vous pouvez utiliser la macro PRIuPTR définie dans :

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

    Si vous voulez vraiment être sûr, uintmax_t sur uintmax_t et utilisez PRIuMAX :

     printf("If the answer is %" PRIuMAX " then what is the question?\n", static_cast(a)); 

    Puisque vous utilisez C ++, pourquoi ne pas utiliser IOStreams? Cela devrait comstackr sans avertissements et faire le bon choix pour le type, tant que vous n’utilisez pas une implémentation C ++ sans cervelle qui ne définit pas un operator << for size_t .

    Lorsque la sortie doit être effectuée avec printf() , vous pouvez toujours la combiner avec IOStreams pour obtenir un comportement sécurisé:

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

    Ce n'est pas super efficace, mais votre cas ci-dessus concerne les E / S de fichiers, c'est donc votre goulot d'étranglement, pas ce code de formatage de chaîne.

    voici une solution possible, mais ce n’est pas tout à fait une belle ..

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

    Le type effectif sous-jacent size_t dépend de l’implémentation . C Standard le définit comme le type renvoyé par l’opérateur sizeof; en plus d’être non signé et une sorte de type intégral, le size_t peut être à peu près n’importe quelle taille pouvant accueillir la plus grande valeur attendue par sizeof ().

    Par conséquent, la chaîne de format à utiliser pour une taille_t peut varier en fonction du serveur. Il devrait toujours avoir le “u”, mais peut-être l ou d ou peut-être autre chose …

    Une astuce pourrait être de le convertir au type intégral le plus important sur la machine, en garantissant aucune perte dans la conversion, puis en utilisant la chaîne de format associée à ce type connu.

    La bibliothèque de format C ++ fournit une implémentation rapide portable (et sûre) de printf y compris le modificateur z pour size_t :

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

    En outre, il prend en charge la syntaxe de format de type Python et capture les informations de type afin de ne pas avoir à les fournir manuellement:

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

    Il a été testé avec les principaux compilateurs et fournit une sortie cohérente sur toutes les plates-formes.

    Disclaimer : Je suis l’auteur de cette bibliothèque.