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 是正确的!但我不知道是什么导致了这个问题,我应该修改什么以便我可以正确使用 atomic ...谢谢!

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.


在我的平台上,类型intunsigned long long布局不兼容,因此当 printf 尝试访问由%d实际传递的参数为结果时指定的可变参数时uint64_t,结果将是未定义的行为。

printf 的普通格式化程序,例如%dand%llu用于内置类型,例如intor unsigned long long。stdint.h 中的类型不是内置的,在不同的平台上可能对应不同的内置类型,每个平台需要不同的格式化程序。

例如int64_t,可能与int一个平台上的相同,而与long long不同平台上的相同。由于要int在 printf 中使用格式说明符%d并使用long long格式说明符%lld,因此您不能使用 stdint 类型和普通格式说明符编写可移植代码。


相反,头文件 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 库的优点之一是这种错误是不可能的。

于 2013-06-20T05:05:03.710 回答