【发布时间】:2020-09-04 17:39:43
【问题描述】:
我正在尝试解决与GCC conversion warning when assigning to a bitfield 几乎完全相同的问题,但似乎没有任何解决方案有效。与链接的问题一样,gcc 版本似乎没有帮助,gccs 10.1、9.1、8.2、8.1、7.1、6.1、5.1 和 4.9.1 都失败了。
typedef unsigned int uint;
struct foo { uint a:8; uint b:24; };
void bar(struct foo num, uint x) {
num.b = (5U << 1) | (1 & 1);
num.b = ((uint)(((5U << 1) | (uint)((uint) x & 1))) & 0xffffffU);
num.a = (unsigned char)x;
}
Watch it fail on Godbolt. 编译器产生:
In function 'bar':
5:13: error: conversion from 'unsigned int' to 'unsigned int:24' may change value [-Werror=conversion]
5 | num.b = ((uint)(((5U << 1) | (uint)((uint) x & 1))) & 0xffffffU);
| ^
如您所见,我尝试显式掩码为 24 位,将随机内容转换为无符号整数,以及上述几乎所有的组合(例如,仅掩码、仅转换、在看似任何相关位置进行转换等)。第一个 num.b 赋值适用于常量,但添加变量会使一切变得混乱。
我已经通过如下 pragma 解决了这个问题,但这不是一个非常令人满意的解决方案。
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wconversion"
num.b = (5U << 1) | (x & 1U);
#pragma GCC diagnostic pop
@Artyr 在对该问题的评论中提出了解决方案。如果他把它变成一个答案,我会接受它。但是,在调查该解决方案时,我发现了另一种解决问题的方法,真的没有意义。在下面的示例中,只有最后一个分配失败。
uint z = 5U;
num.b = (5U << 1) | (1 & 1); //OK
num.b = ((z << 1) | (x & 1)) & 0xffffffU; //OK
num.b = ((5U << 1) | (x & 1)) & 0xffffffU; //BAD
我不明白为什么添加另一个从同一个常量静态分配的变量 z 可以解决问题。为什么常量和变量的组合会导致问题?
【问题讨论】:
-
你似乎在自找麻烦。我很难用 GCC 8.3.1 重现这个:用
-Wall -Wextra -pedantic编译没有发出你呈现的转换警告。显然,原因是该警告不包括在任何这些警告组中。仅当我特别要求-Wconversion或-Werror=conversion时才重现该问题。所以不要那样做。警告不包含在上述任何组中是一个好兆头,表明它仅用于特殊目的。 -
@ryyker,
1的类型为int,而1u的类型为unsigned int,但这实际上并没有像 OP 代码中使用的那样产生任何区别。 -
num->b = (5U << 1) | (_Bool)(x & 1);似乎可以修复它。num->b = x & 1 ? 10 : 11也有效,但这显然不是在所有情况下都有效。 -
(VERSION << 1) + !!(flag & 1)为我工作(假设 VERSION 是5u的预处理器宏) -
您很可能会在 GCC 的
-Wconversion实现中遇到错误。如果它在最新的 GCC 中重现,您可以在 GCC Bugzilla 中提交错误(如果没有,则表示已修复)。目前,您唯一的选择是通过编译指示或 Makefile 禁用此特定文件的-Wconversion来解决此问题。
标签: c gcc compiler-warnings suppress-warnings