如何定义uint64_t常量?

7
我在我的C++程序中有uint64_t常量(使用QtCreator 4.6.1中的clang 6.0.1)。
例如:
uint64_t a = 0xffffffffffffffffULL;

问题是,我在IDE中收到以下警告:
Warning: implicit conversion from 'unsigned long long' to 'uint64_t' (aka 'unsigned long')

我也试图将其更改为以下内容,但没有成功:

uint64_t a = UINT64_C(0xffffffffffffffff);
uint64_t a = 0xffffffffffffffffUL;

我有使用 C++14 标准和选项 -Wconstant-conversion 进行计算的选择。
检查类型大小:
std::cout << "uint64_t " << sizeof (uint64_t) << std::endl; 
std::cout << "unsigned long " << sizeof (unsigned long) << std::endl;
std::cout << "unsigned long long " << sizeof (unsigned long long) << std::endl;

结果:

uint64_t 8  
unsigned long 8
unsigned long long 8

有任何想法如何修复这个问题和为什么IDE认为正在进行大小转换?
编辑:我刚检查了宏展开:
define UINT64_C(c)  c ## UL

这意味着提供的示例应该可以工作,但实际上并没有。
uint64_t a = 0xffffffffffffffffUL;

2
答案在你的警告信息中!仔细阅读它。 - Some programmer dude
1
可能相关:问题1问题2 - njuffa
@πάνταῥεῖ,64位带有LP64/IPL64数据模型:https://en.wikipedia.org/wiki/64-bit_computing#64-bit_data_models。本机Windows使用LLP64,UL后缀在LP64和LLP64模型之间不可移植。 - osgx
3
如果你的编译器将0xffffffffffffffffUL视为unsigned long long常量(因为你说错误仍然是“从'unsigned long long'转换”),那么你的unsigned long类型不具有64位。如果您的头文件仍将uint64_t定义为unsigned long,则可能存在严重问题。您是否无意中使用了另一个平台的头文件?但这与测试程序的输出不符。 - user743382
1
@hvd 这似乎确实是混合标头的问题。我尝试将定义复制到另一个文件中,警告就不会显示出来。 - Ross
显示剩余8条评论
5个回答

3

感谢 @hvd 的评论,此警告已得到解决。

检查了所有包含的头文件。由于某些原因,同时包含了 stdint.hcstdint。我只留下了 cstdint。它们可能来自不同的平台并具有不同的定义。

有效示例:

uint64_t v0 = UINT64_C(0x736f6d6570736575);

宏是邪恶的,而且几乎从来不需要使用。 - Sid S
1
如果只包含 stdint.h 会发生什么?或者只包含 cstdint 呢?很可能,对于这两种情况中的一种,你会收到相同的虚假警告(如果两个都被包含,则不应该有问题)。“它们可能来自不同的平台并具有不同的定义。”:这意味着你的安装是不正确的。 - geza

3

unsigned long long 至少有 64 位,所以它可能比 uint64_t 更大

我会这样写(请注意使用 constexpr 因为它是一个常量):

#include <cinttypes>
#include <limits>
constexpr auto a = std::numeric_limits<std::uint64_t>::max();

如果要以可移植的方式定义一个非最大值的 uint64_t 常量,只需删除末尾的 ULL 部分即可:

constexpr std::uint64_t b = 0x12345;

等于或更大。64位,不是字节。取决于数据模型:https://en.wikipedia.org/wiki/64-bit_computing#64-bit_data_models。如何以可移植的方式定义非最大常量? - osgx
@bit_data_models 很好地捕捉到了字节转换为比特的问题。你所说的“等于或更大”是什么意思?我在我的回答中说了“至少”,这与等于或更大是相同的,不是吗? - Olivier Sohn

0
编译器警告您在C++中存在类型之间的隐式转换,这些类型的大小不能保证相同。可能的解决方法是使其显式:
uint64_t a = static_cast<uint64_t>(0xffffffffffffffffULL);

0

这是一种实现方式:

auto a = static_cast<uint64_t>(-1);

-1

首先要注意的是,您不需要使用LL后缀。

整数字面量会自动具有可以容纳该数字的类型。请查看this表以获取确切的类型。唯一的例外是,如果您指定的十进制字面量仅适合于unsigned long long int,那么您需要指定u后缀。

现在,可以通过强制转换轻松删除警告:

uint64_t a = (uint64_t)0xffffffffffffffff;

或者如果您不喜欢C语言的强制转换,则可以使用static_cast

uint64_t a = static_cast<uint64_t>(0xffffffffffffffff);


到目前为止,这是理论,但您的编译器/安装存在一些问题。如果您对此收到了隐式转换警告:

uint64_t a = 0xffffffffffffffffUL;

其中uint64_tunsigned long,那么这意味着0xffffffffffffffffUL实际上变成了unsigned long long int。但它不应该是这样的,因为sizeof(unsigned long)已经是8了。如果编译器和安装正确,这显然是不可能的情况。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接