Ich habe einen C++ - Code, der einen size_t
Ausgibt:
size_t a;
printf("%lu", a);
Ich möchte, dass dies ohne Warnungen auf 32- und 64-Bit-Architekturen kompiliert wird.
Wenn dies C99 wäre, könnte ich printf("%z", a);
verwenden. Aber AFAICT %z
Existiert in keinem Standard-C++ - Dialekt. Also muss ich stattdessen tun
printf("%lu", (unsigned long) a);
das ist wirklich hässlich.
Wenn es keine Möglichkeit gibt, size_t
In der Sprache zu drucken, frage ich mich, ob es möglich ist, einen printf-Wrapper oder etwas Ähnliches zu schreiben, bei dem die entsprechenden Abdrücke auf size_t
Eingefügt werden, um Fehldarstellungen zu beseitigen Compiler-Warnungen unter Beibehaltung der guten.
Irgendwelche Ideen?
Die meisten Compiler haben ihre eigenen Bezeichner für size_t
und ptrdiff_t
Argumente, Visual C++ zum Beispiel verwenden% Iu und% Id, ich denke, dass gcc es Ihnen ermöglichen wird,% zu und% zd zu verwenden.
Sie könnten ein Makro erstellen:
#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
Verwendung:
size_t a;
printf(JL_SIZE_T_SPECIFIER, a);
printf("The size of a is " JL_SIZE_T_SPECIFIER " bytes", a);
Der printf
Formatbezeichner %zu
funktioniert gut auf C++ Systemen; es besteht keine Notwendigkeit, es komplizierter zu machen.
C++ 11
C++ 11 importiert C99, daher sollte std::printf
Den Formatbezeichner C99 %zu
Unterstützen.
C++ 98
Auf den meisten Plattformen sind size_t
Und uintptr_t
Gleichwertig. In diesem Fall können Sie das in <cinttypes>
Definierte Makro PRIuPTR
verwenden:
size_t a = 42;
printf("If the answer is %" PRIuPTR " then what is the question?\n", a);
Wenn Sie wirklich sicher sein möchten, geben Sie uintmax_t
Ein und verwenden Sie PRIuMAX
:
printf("If the answer is %" PRIuMAX " then what is the question?\n", static_cast<uintmax_t>(a));
Warum nicht IOStreams verwenden, da Sie C++ verwenden? Das sollte ohne Warnungen kompiliert werden und die richtige typabhängige Sache machen, solange Sie keine C++ - Implementierung verwenden, die keinen operator <<
Für size_t
Definiert.
Wenn die eigentliche Ausgabe mit printf()
erfolgen muss, können Sie sie trotzdem mit IOStreams kombinieren, um ein typsicheres Verhalten zu erzielen:
size_t foo = bar;
ostringstream os;
os << foo;
printf("%s", os.str().c_str());
Es ist nicht besonders effizient, aber in Ihrem obigen Fall geht es um Datei-E/A. Das ist also Ihr Engpass, nicht dieser Code zur Formatierung von Zeichenfolgen.
hier ist eine mögliche Lösung, aber es ist nicht ganz schön.
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 ) );
Der zugrunde liegende effektive Typ size_t ist implementierungsabhängig. C Standard definiert es als den Typ, der vom sizeof-Operator zurückgegeben wird. Abgesehen davon, dass size_t nicht vorzeichenbehaftet und eine Art ganzzahliger Typ ist, kann es sich bei size_t um so ziemlich alles handeln, was der größte Wert sein kann, der von sizeof () erwartet wird.
Infolgedessen kann die für size_t zu verwendende Formatzeichenfolge je nach Server variieren. Es sollte immer das "u" haben, kann aber l oder d oder vielleicht etwas anderes sein ...
Ein Trick könnte darin bestehen, es auf den größten integralen Typ auf der Maschine umzuwandeln, ohne Verluste bei der Konvertierung zu verursachen, und dann die Formatzeichenfolge zu verwenden, die diesem bekannten Typ zugeordnet ist.
Die Bibliothek C++ Format bietet eine schnelle portable (und sichere) Implementierung von printf
, einschließlich des Modifikators z
für size_t
:
#include "format.h"
size_t a = 42;
int main() {
fmt::printf("%zu", a);
}
Darüber hinaus unterstützt es die Python-ähnliche Format-String-Syntax und erfasst Typinformationen, sodass Sie diese nicht manuell eingeben müssen:
fmt::print("{}", a);
Es wurde mit großen Compilern getestet und bietet plattformübergreifende konsistente Ausgabe.
Haftungsausschluss : Ich bin der Autor dieser Bibliothek.