为什么没有类型转换警告?

4

我有以下一段C代码,启用了Clang中的-Wconversion:

uint8_t num_ch = get_num_channels();
uint64_t test_mask = 1 << num_ch;

我原本希望会出现某种警告,因为1是隐式的“signed int”,然后被赋值给uint64_t,但编译器没有抱怨:(

我错过了什么?


1
num_ch 是常量吗?无论如何,这里可能存在的问题不是类型转换,而是移位有符号的 int - Eugene Sh.
另一个问题是,即使是1U << 40也不能做你期望的事情。 - 0___________
更糟糕的是,当您实际上移动负值时,它甚至不会抱怨:https://www.godbolt.org/z/eh6v9Y - Jerry Jeremiah
有趣!MSVC 给出了警告:warning C4365: 'initializing': conversion from 'int' to 'uint64_t', signed/unsigned mismatch。(我已经声明:uint64_t num_ch = 3;)。它还给出了:**warning C4334: '<<': result of 32-bit shift implicitly converted to 64 bits (was 64-bit shift intended?)**。 - Adrian Mole
3
使用带有 -Wconversion 选项的 gcc 4.8.5 会对此发出警告。 - dbush
显示剩余10条评论
1个回答

5

为什么没有类型转换警告?

简短回答:因为您使用的clang/LLVM版本存在缺陷(有些人甚至称其为错误)。

讨论/解释/推理

问题源于位移表达式s << u,其中s有符号整数类型,u无符号类型。现在,根据this C11 Draft Standard(我加粗了):

6.5.7 位移运算符
...
3 对每个操作数执行整数提升。结果的类型是所提升的操作数的类型。

这意味着表达式的结果是一个带符号的整数。因此,我应该指出,我正在使用(并假设)一个使用32位“基本”int类型的平台。还要注意,没有u后缀的整数常量是有符号类型。 注意:虽然我无法访问OP的嵌入式系统,也无法使用本地GCC编译器,但我可以使用Visual Studio 2019最新版本提供的clang-cl编译器来复现问题(16.7.2 - 找到版本后我会添加clang版本)。 以下代码确实生成了预期的警告(实际上,显示了两个警告):
#include <stdio.h>
#include <stdint.h>

int main()
{
    uint64_t test_mask = 1 << (uint8_t)(31); // Warnings here, as expected.
    printf("%016llX\n", test_mask);
    return 0;
}

警告:

警告:带符号移位结果(0x80000000)设置了移位表达式类型(“int”)的符号位并变为负数[-Wshift-sign-overflow]
警告:隐式转换更改了有符号性:'int'到'uint64_t'(也称为'unsigned long long')[-Wsign-conversion]

此外,printf 调用的输出为 FFFFFFFF80000000,这说明为什么警告很重要:在一个 32 位的 int 上进行位移后产生了负值,然后当其升级到 64 位时进行符号扩展,从而“破坏”了预期的结果(如果将字面量 1 简单地更改为 1u,从而避免符号扩展,则预期结果将为 0000000080000000)。

然而!如果对代码进行了非常微小的(有些人甚至会说是无关紧要的)更改,将位移操作的右操作数从一个字面值(常量)改为一个完全等效的变量,如下所示,则来自clang-cl的警告消失了(但输出仍然“损坏”-因此执行的操作相同)。

int main()
{
    uint8_t num_ch = 31;
    uint64_t test_mask = 1 << num_ch; // No warning here!
    printf("%016llX\n", test_mask);
    return 0;
}

也许这不是最有帮助的答案,但除了向LLVM团队报告问题外,还能做什么呢?我肯定会提交这样的报告,因为OP发布的代码可能会导致一些严重问题,应该由启用完整警告的编译器检测和指示(即使对于第二个代码片段,MSVC也会发出警告)。

当你考虑到gcc在升级的10版本中删除了警告,而9.3版本仍然发出警告时,这似乎确实是一个bug,但更多的疑问出现了。https://godbolt.org/z/33M4dn - anastaciu

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