首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >c++11中原子fetch_add中的int64_t和int的奇怪行为

c++11中原子fetch_add中的int64_t和int的奇怪行为
EN

Stack Overflow用户
提问于 2013-06-20 11:03:49
回答 1查看 931关注 0票数 0

我在MinGW中有以下c++源代码测试,g++版本是4.8.1 : compiled : g++ -std=c++11 int64test.cpp -o int64test.exe

代码语言:javascript
运行
复制
#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)) ;
}

答案是:

代码语言:javascript
运行
复制
(1000)(1001)(1002)(1003)
(1000)(0)(1001)(0)

显然,原子uint64_t是错误的,而原子int是正确的!但是我不知道是什么导致了这个问题,我应该修改什么才能正确地使用原子...thanks!

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2013-06-20 13:05:04

您使用的行打印uint64_t数据的格式不正确。当我编译你的代码时,我的编译器会产生以下警告:

代码语言:javascript
运行
复制
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

注意:您可以使用标志-Wformat,或者更好的-Wall,在GCC 4.8.1中启用类似的格式检查警告。

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

printf的常规格式化程序(如%d%llu )用于内置类型,如intunsigned long long。stdint.h中的类型不是内置的,可能对应于不同平台上的不同内置类型,在每个平台上需要不同的格式化程序。

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

相反,头文件inttyes.h随包含正确格式说明符的宏一起提供。uint64_t的宏是PRIu64。此宏将被定义为您的平台上的任何正确格式说明符。像这样使用它:

代码语言:javascript
运行
复制
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库的一个优点是这种错误是不可能的。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/17204625

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档