web-dev-qa-db-ja.com

OS Xでのprintfと%lluと%luの比較

重複の可能性:
fuint64_tをprintする方法は?

64ビットMac(Clangを使用)ではuint64_tタイプがunsigned long longであるのに対し、64ビットUbuntuではuint64_tタイプがunsigned longであるのはなぜですか?

これにより、printf呼び出しを取得して、両方の環境でコンパイラー警告を出さないようにする(または実際に機能するようにする)ことが非常に困難になります。

マクロを使用して正しい文字列(#define LU%lluまたは%luのいずれか、およびその過程でprintf文字列を少し醜くする)を選択しようとすることができますが、 Macは64ビットのワードサイズを持っていますが(したがって、_LP64が定義されUINTPTR_MAX != 0xffffffff)、それでも64ビットのint型にはlong longを使用します。

// printf macro switch (for the uint64_t's)
#if UINTPTR_MAX == 0xffffffff 
   // 32-bit
#  define LU "%llu"
#else 
   // assume 64-bit
   // special case for OS X because it is strange
   // should actually check also for __MACH__ 
#  ifdef __Apple__
#    define LU "%llu"
#  else
#    define LU "%lu"
#  endif
#endif
9
Steven Lu

マクロは<cinttypes>ですでに定義されています。試してみてください

printf("%"PRIu64, x);

または、さらに良いことに、次のようなC++機能を使用します

std::cout << x;

これにより、変数タイプに適切な<<演算子が選択されます。

6
Bo Persson

答えは、静的キャストを介して宣伝することです。

some_type i = 5;
printf("our value is: %llu", (unsigned long long)i);
3
Grady Player

_uint64_t_の基になるタイプは、実際には64ビットである限り、実装がどのようなものでもかまいません。

明らかに、C++では、問題が解消されるため、printfの代わりにiostreamを使用することをお勧めします。ただし、printfに渡された値をキャストするだけで、タイプを常に正しくすることができます。

printf("%llu", static_cast<unsigned long long>(value));

1
Mark B

残念ながら、標準はこれらのタイプのサイズについてあまり具体的ではありません...唯一の保証はsizeof(int) <= sizeof(long) <= sizeof(long long)です。

あなたが言ったようにマクロを使うことができます、あるいは%zu%juタイプ(OSXでは両方とも64ビット)を印刷するために使われるsize_tまたはuintmax_tを使ってみることができます、Ubuntuでテストしていません)。他に選択肢はないと思います。

0
daxnitro

他の人からBOOSTを使うように言われると思います。したがって、BOOSTに依存しないソリューションを提供するために:

私は同じ問題に頻繁に遭遇したので、%llu%luなどのブランドの代わりに%sにフィードする独自のヘルパーマクロをあきらめて作成しました。また、適切な形式の文字列デザインを維持し、より優れた(そしてより一貫性のある)16進およびポインターの印刷を提供するのに役立つこともわかりました。 2つの注意点があります。

  1. 追加の書式設定パラメーター(左/右揃え、パディングなど)を簡単に組み合わせることができませんが、LUマクロでも実際に組み合わせることができません。

  2. このアプローチでは、文字列のフォーマットと印刷のタスクにオーバーヘッドが追加されます。ただし、パフォーマンスが重要なアプリを作成しましたが、MicrosoftのVisual C++デバッグビルド(内部検証と破損チェックがすべて行われるため、ヒープメモリの割り当てと解放に通常の約200倍の時間がかかる)を除いて、問題であることに気づいていません。

比較は次のとおりです。

printf( "Value1: " LU ", Value2: " LU, somevar1, somevar2 );

vs.

printf( "Value1: %s, Value2: %s", cStrDec(somevar1), cStrDec(somevar2) );

それを機能させるために、私は次のようなマクロとテンプレートのセットを使用しました。

#define cStrHex( value )        StrHex    ( value ).c_str()
#define cStrDec( value )        StrDecimal( value ).c_str()

std::string StrDecimal( const uint64_t& src )
{
    return StrFormat( "%u%u", uint32_t(src>>32), uint32_t(src) );
}

std::string StrDecimal( const int64_t& src )
{
    return StrFormat( "%d%u", uint32_t(src>>32), uint32_t(src) );
}

std::string StrDecimal( const uint32_t& src )
{
    return StrFormat( "%u", src );
}

std::string StrDecimal( const int32_t& src )
{
    return StrFormat( "%d", src );
}

std::string StrHex( const uint64_t& src, const char* sep="_" )
{
    return StrFormat( "0x%08x%s%08x", uint32_t(src>>32), sep, uint32_t(src) );
}

std::string StrHex( const int64_t& src, const char* sep="_" )
{
    return StrFormat( "0x%08x%s%08x", uint32_t(src>>32), sep, uint32_t(src) );
}

// Repeat implementations for int32_t, int16_t, int8_t, etc.
// I also did versions for 128-bit and 256-bit SIMD types, since I use those.
// [...]

私の文字列フォーマット関数は、std :: stringに直接フォーマットする現在推奨されている方法に基づいています。これは次のようになります。

std::string StrFormatV( const char* fmt, va_list list )
{
#ifdef _MSC_VER
    int destSize = _vscprintf( fmt, list );
#else
    va_list l2;
    va_copy(l2, list);
    int destSize = vsnprintf( nullptr, 0, fmt, l2 );
    va_end(l2);
#endif
    std::string result;
    result.resize( destSize );
    if (destSize!=0)
            vsnprintf( &result[0], destSize+1, fmt, list );
    return result;
}

std::string StrFormat( const char* fmt, ... )
{
    va_list list;
    va_start( list, fmt );
    std::string result = StrFormatV( fmt, list );
    va_end( list );

    return *this;
}
0
jstine