【问题标题】:Why no type conversion warning?为什么没有类型转换警告?
【发布时间】:2020-08-27 21:59:27
【问题描述】:

我有以下 C 代码的 sn-p,在 Clang 中启用了 -Wconversion:

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

我希望这会引发某种警告,因为 1 是隐含的“有符号整数”,然后被分配给 uint64_t,但编译器没有抱怨:(

我错过了什么?

【问题讨论】:

  • num_ch 是常量吗?无论如何,这里可能的问题不是类型转换,而是转移签名的int
  • 另一个问题是即使 1U
  • 比这更糟糕的是——当你真正转移一个负值时它甚至不会抱怨:godbolt.org/z/eh6v9Y
  • 有趣! MSVC 给出:警告 C4365:“正在初始化”:从“int”转换为“uint64_t”,有符号/无符号不匹配。 (我已经声明:uint64_t num_ch = 3;)。它还给出:警告 C4334:'。
  • gcc 4.8.5 with -Wconversion 对此发出警告。

标签: c gcc embedded clang


【解决方案1】:

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

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

讨论/解释/推理

问题源于对位移表达式s &lt;&lt; u 的求值,其中s有符号 整数类型,u无符号类型。现在,根据this C11 Draft Standard(我的粗体字):

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

这意味着表达式的结果是一个有符号整数。今后,我应该指出,我正在使用(并假设)一个使用 32 位“基本”int 类型的平台。另请注意,不带u 后缀的整数常量有符号 类型。

注意:虽然我无法访问 OP 的嵌入式系统,也无法访问本地 GCC 编译器,但我仍然可以使用最新版本的 Visual Studio 2019(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甚至对第二个代码 sn-p 发出警告。

【讨论】:

  • 这似乎是一个错误,但是当您考虑到 gcc 在升级的 10 版本中删除了警告而 9.3 版本仍然发出警告时,就会出现更多疑问godbolt.org/z/33M4dn
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多