J'ai du code C++ qui imprime un size_t
:
size_t a;
printf("%lu", a);
J'aimerais que cela compile 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 à la place, 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 dans le langage, je me demande s'il est possible d'écrire un wrapper printf ou un tel tel qui insérera les transtypages appropriés sur size_t
S afin d'éliminer les parasites avertissements du compilateur tout en conservant les bons.
Des idées?
La plupart des compilateurs ont leur propre spécificateur pour size_t
et ptrdiff_t
arguments, Visual C++ utilise par exemple% Iu et% Id respectivement, je pense que gcc vous permettra d'utiliser% zu et% zd.
Vous pouvez 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 spécificateur de format printf
%zu
fonctionnera bien sur les systèmes C++; il n'est pas nécessaire de le rendre plus compliqué.
C++ 11
C++ 11 importe C99 donc std::printf
devrait prendre en charge le C99 %zu
spécificateur de format.
C++ 98
Sur la plupart des plateformes, size_t
et uintptr_t
sont équivalents, auquel cas vous pouvez utiliser la macro PRIuPTR
définie dans <cinttypes>
:
size_t a = 42;
printf("If the answer is %" PRIuPTR " then what is the question?\n", a);
Si vous vraiment voulez être en sécurité, transformez en uintmax_t
et utilisez PRIuMAX
:
printf("If the answer is %" PRIuMAX " then what is the question?\n", static_cast<uintmax_t>(a));
Puisque vous utilisez C++, pourquoi ne pas utiliser IOStreams? Cela devrait se compiler sans avertissements et faire la bonne chose en fonction du type, tant que vous n'utilisez pas une implémentation C++ morte de cerveau qui ne définit pas un operator <<
Pour size_t
.
Lorsque la sortie réelle doit être effectuée avec printf()
, vous pouvez toujours la combiner avec IOStreams pour obtenir un comportement de type sécurisé:
size_t foo = bar;
ostringstream 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 jolie ..
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, la taille_t peut être à peu près tout ce dont la taille peut contenir la plus grande valeur attendue par sizeof ().
Par conséquent, la chaîne de format à utiliser pour un size_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 en le plus grand type intégral sur la machine, en assurant aucune perte dans la conversion, puis en utilisant la chaîne de format associée à ce type connu.
La bibliothèque Format C++ fournit une implémentation portable rapide (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 plus de cela, il prend en charge la syntaxe de chaîne de format de type Python et capture les informations de type afin que vous n'ayez pas à les fournir manuellement:
fmt::print("{}", a);
Il a été testé avec les principaux compilateurs et fournit une sortie cohérente sur toutes les plateformes.
Avertissement : Je suis l'auteur de cette bibliothèque.