0

Winx の MinGW に次の c++ ソース テストがあります。g++ バージョンは 4.8.1 です: コンパイル済み: g++ -std=c++11 int64test.cpp -o int64test.exe

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sched.h>
#include <errno.h>
#include <string.h>
#include <errno.h>
#include <atomic>
#include <iostream> 
#include <cstdint>

using namespace std ;

int main(int argc, const char *argv[])
{
    atomic<unsigned int> uintlocal1(1000) ;
    unsigned int uint1,uint2,uint3 ;
    uint1 = uintlocal1.fetch_add(1) ;
    uint2 = uintlocal1.fetch_add(1) ;
    uint3 = uintlocal1.fetch_add(1) ;   
    printf("(%d)(%d)(%d)(%d)\n",uint1,uint2,uint3,unsigned(uintlocal1)) ;

    atomic<uint64_t> uint64local1(1000) ;
    uint64_t u1,u2,u3 ;
    u1 = uint64local1.fetch_add(1) ;
    u2 = uint64local1.fetch_add(1) ;
    u3 = uint64local1.fetch_add(1) ;    
    printf("(%d)(%d)(%d)(%d)\n",u1,u2,u3,unsigned(uint64local1)) ;
}

答えは:

(1000)(1001)(1002)(1003)
(1000)(0)(1001)(0)

明らかに、アトミックな uint64_t は間違っていますが、アトミックな int は正しいです!! しかし、この問題の原因がわかりません。アトミックを正しく使用できるようにするには、何を変更すればよいですか...ありがとう!!

4

1 に答える 1

2

ライン印刷uint64_tデータに不適切な形式を使用しています。コードをコンパイルすると、コンパイラは次の警告を生成します。

main.cpp:18:33: warning: format specifies type 'int' but the argument has type 'uint64_t' (aka 'unsigned long long') [-Wformat]
    printf("(%d)(%d)(%d)(%d)\n",u1,u2,u3,unsigned(uint64local1)) ;
             ~~                 ^~
             %llu
main.cpp:18:36: warning: format specifies type 'int' but the argument has type 'uint64_t' (aka 'unsigned long long') [-Wformat]
    printf("(%d)(%d)(%d)(%d)\n",u1,u2,u3,unsigned(uint64local1)) ;
                 ~~                ^~
                 %llu
main.cpp:18:39: warning: format specifies type 'int' but the argument has type 'uint64_t' (aka 'unsigned long long') [-Wformat]
    printf("(%d)(%d)(%d)(%d)\n",u1,u2,u3,unsigned(uint64local1)) ;
                     ~~               ^~
                     %llu

注: GCC 4.8.1 で同様の形式チェック警告を有効にするには、フラグ を使用する-Wformatか、さらに良いことにを使用し-Wallます。


私のプラットフォームでは、型intと型unsigned long longはレイアウト互換性がないため、printf が指定された vararg にアクセスしようとすると%d、実際に渡された引数はuint64_t未定義の動作になります。

%dやなどの printf の通常のフォーマッタは、または%lluなどの組み込み型に使用されます。stdint.h の型は組み込まれておらず、プラットフォームごとに異なるフォーマッタが必要なため、さまざまなプラットフォームのさまざまな組み込み型に対応している可能性があります。intunsigned long long

たとえば、あるプラットフォームと同じであり、別のプラットフォームとint64_t同じである可能性があります。printf で使用するには書式指定子を使用し、使用するには書式指定子を使用するため、stdint 型と通常の書式指定子を使用して移植可能なコードを作成することはできません。intlong longint%dlong long%lld


代わりに、ヘッダー inttypes.h に、正しい書式指定子を含むマクロが提供されます。のマクロuint64_tは PRIu64 です。このマクロは、プラットフォーム上の正しいフォーマット指定子が何であれ定義されます。次のように使用します。

printf("(%" PRIu64 ")(%" PRIu64 ")(%" PRIu64 ")(%u)\n",u1,u2,u3,unsigned(uint64local1));

マクロと引用符で囲まれた文字列フラグメントの間にスペースを入れてください。そうしないと、C++11 でマクロが正しく機能しません。

通常のフォーマッタに関する便利なリファレンスは次のとおりです: http://en.cppreference.com/w/cpp/io/c/fprintf

stdint.h の型とフォーマッタのリファレンスは次のとおりです: http://en.cppreference.com/w/cpp/types/integer


注: printf で不適切な書式指定子を使用すると、間違いを犯しやすく、未定義の動作につながります。iostream ライブラリの利点の 1 つは、この種の間違いが起こらないことです。

于 2013-06-20T05:05:03.710 に答える