_size_t
_を出力するC++コードがいくつかあります。
_size_t a;
printf("%lu", a);
_
32ビットアーキテクチャと64ビットアーキテクチャの両方で、警告なしにこれをコンパイルしたいと思います。
これがC99であれば、printf("%z", a);
を使用できます。しかし、AFAICT _%z
_は、標準C++方言には存在しません。だから代わりに、私はしなければならない
_printf("%lu", (unsigned long) a);
_
これは本当にいです。
言語に組み込まれた_size_t
_ sを印刷する機能がない場合、printfラッパーまたは適切なキャストを_size_t
_ sに挿入して、偽のコンパイラ警告を排除するようなものを作成することは可能だろうか良いものを維持します。
何か案は?
ほとんどのコンパイラは、size_t
およびptrdiff_t
引数に独自の指定子を持っています。たとえば、Visual C++はそれぞれ%Iuと%Idを使用します。gccを使用すると%zuと%zdを使用できると思います。
マクロを作成できます:
#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
使用法:
size_t a;
printf(JL_SIZE_T_SPECIFIER, a);
printf("The size of a is " JL_SIZE_T_SPECIFIER " bytes", a);
printf
形式指定子%zu
はC++システムで正常に動作します。より複雑にする必要はありません。
C++ 11
C++ 11はC99をインポートするため、std::printf
はC99 %zu
形式指定子をサポートする必要があります。
C++ 98
ほとんどのプラットフォームでは、size_t
とuintptr_t
は同等です。この場合、<cinttypes>
で定義されている PRIuPTR
マクロを使用できます。
size_t a = 42;
printf("If the answer is %" PRIuPTR " then what is the question?\n", a);
本当に安全にしたい場合は、uintmax_t
にキャストしてPRIuMAX
を使用します:
printf("If the answer is %" PRIuMAX " then what is the question?\n", static_cast<uintmax_t>(a));
C++を使用しているので、なぜIOStreamsを使用しないのですか? _operator <<
_に対して_size_t
_を定義しない脳死のC++実装を使用していない限り、警告なしでコンパイルし、適切な型認識機能を実行する必要があります。
実際の出力をprintf()
で行う必要がある場合でも、IOStreamsと組み合わせて、タイプセーフな動作を取得できます。
_size_t foo = bar;
ostringstream os;
os << foo;
printf("%s", os.str().c_str());
_
これは非常に効率的ではありませんが、上記のケースではファイルI/Oを扱っているため、この文字列フォーマットコードではなく、それがボトルネックです。
ここに可能な解決策がありますが、それはかなりきれいなものではありません。
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 ) );
基礎となる有効なタイプsize_tは実装依存。 C標準では、sizeof演算子によって返される型として定義しています。符号なしと整数型のほかに、size_tは、sizeof()によって返されると予想される最大値に対応できるサイズであれば、ほとんど何でもかまいません。
したがって、size_tに使用されるフォーマット文字列は、サーバーによって異なる場合があります。それは常に「u」を持っているはずですが、lまたはdまたは多分何かかもしれません...
トリックは、マシン上で最大の整数型にキャストし、変換の損失がないことを確認してから、この既知の型に関連付けられたフォーマット文字列を使用することです。
C++ Format ライブラリは、size_t
のprintf
修飾子を含むz
の高速で移植可能な(かつ安全な)実装を提供します。
#include "format.h"
size_t a = 42;
int main() {
fmt::printf("%zu", a);
}
それに加えて、Pythonのような形式文字列構文をサポートし、型情報をキャプチャするため、手動で入力する必要はありません。
fmt::print("{}", a);
主要なコンパイラでテストされており、プラットフォーム間で一貫した出力を提供します。
免責事項:私はこのライブラリの著者です。