webentwicklung-frage-antwort-db.com.de

Bereinigen Sie den Code für printf size_t in C ++ (oder: Das nächste Äquivalent von C99% z in C ++)

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?


Bearbeiten
94
Justin L.

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

Der printf Formatbezeichner %zu funktioniert gut auf C++ Systemen; es besteht keine Notwendigkeit, es komplizierter zu machen.

66
Will

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

Unter Windows und der Visual Studio-Implementierung von printf

 %Iu

funktioniert bei mir. siehe msdn

16
meissnersd

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.

10
Warren Young

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

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.

3
mjv

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.

3
vitaut