32位GCC无符号Long的支持初始化错误

nwsw7zdq  于 2023-06-23  发布在  其他
关注(0)|答案(1)|浏览(147)

当我编译代码的时候

typedef long long unsigned myuint64;
 myuint64 a[2] = {18446744073709551615, 18446744073709551615}; // error on 32bit gcc
 myuint64 b = 18446744073709551615; // no error

在带有ARM 32-GCC的Godbolt上,我得到错误

(3 warnings for "integer constant is so large that it is unsigned")

error: narrowing conversion of '-1' from 'long long int' to 'myuint64' {aka 'long long unsigned int'} [-Wnarrowing]
    6 |  myuint64 a[2] = {18446744073709551615, 18446744073709551615};
      |                   ^~~~~~~~~~~~~~~~~~~~
error: narrowing conversion of '-1' from 'long long int' to 'myuint64' {aka 'long long unsigned int'} [-Wnarrowing]
    6 |  myuint64 a[2] = {18446744073709551615, 18446744073709551615};

(The number是uint 64的最大值)
我在使用ARM 64-GCC(或32 bit/64 bit Clang或32 bit/64 bit MSVC)时不会出现此错误。但我得到的错误时,使用其他32位GCC变种的Godbolt。

为什么只有这些32位GCC编译器才会出现错误?

我可以用18446744073709551615u来修复它。是否有其他方法可以修复此错误而不更改代码,也不禁用此警告/错误(-Wno-narrowing)?

6ie5vjzr

6ie5vjzr1#

你的代码是否编译取决于__int128是否存在,它只存在于ARM64 GCC。原因是,当你编写一个没有后缀的 * integer-literal * 时,比如u,编译器会从这个列表中选择一个类型,直到该值符合以下类型之一:

  • int
  • long int
  • long long int
  • 一些实现定义的 * 扩展有符号整数 * 类型,例如__int128
  • 见[lex. icon] § 3 *。

您的值18446744073709551615等于264 - 1,因此64位有符号整数不能满足它,但__int128可以。
让我们来看看ARM64 gcc给你的integer字面量的类型:

// warning: integer constant is so large that it is unsigned
void foo(decltype(18446744073709551615)) {}
foo(__int128):
        ret

警告消息与实际情况不符:您可以看到编译器输出一个接受__int128的函数,这是您的文字类型。
使用ARM gcc(32位)编译的相同代码产生:

foo(long long):
        bx lr

在这种情况下,文字太大,无法容纳任何类型,__int128不存在(尝试使用它会产生编译器错误),GCC选择将其视为警告,而不是错误。

为什么你的代码只适用于64位编译器

myuint64 a[2] = {18446744073709551615, 18446744073709551615};

GCC错误地选择long long作为您的文字,即使这段代码格式不佳,并将其转换为-1myuint64是无符号的,因此它不能表示-1,并且列表初始化不允许收缩转换。结果,我们得到一个编译器错误。
在64位编译器上使用__int128,这不是问题,因为我们可以很好地将__int128(18446744073709551615)转换为myuint64(18446744073709551615)

总结

您已经发现了一个不寻常的情况,其中编译器诊断实际上是违反直觉的。忽略这些诊断并了解涉及__int128即可发现问题。
我不知道你可以使用任何编译器标志来修复这个问题,所以我建议使用u后缀作为字面量,在这种情况下编译器可以选择:

  • unsigned int
  • unsigned long int
  • unsigned long long int
  • 一些实现定义的 * 扩展无符号整数 * 类型,例如__uint128

相关问题