【问题标题】:Son of GCC conversion warning when assigning to a bitfield分配给位域时的 GCC 转换警告之子
【发布时间】: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-&gt;b = (5U &lt;&lt; 1) | (_Bool)(x &amp; 1); 似乎可以修复它。 num-&gt;b = x &amp; 1 ? 10 : 11 也有效,但这显然不是在所有情况下都有效。
  • (VERSION &lt;&lt; 1) + !!(flag &amp; 1) 为我工作(假设 VERSION 是 5u 的预处理器宏)
  • 您很可能会在 GCC 的 -Wconversion 实现中遇到错误。如果它在最新的 GCC 中重现,您可以在 GCC Bugzilla 中提交错误(如果没有,则表示已修复)。目前,您唯一的选择是通过编译指示或 Makefile 禁用此特定文件的 -Wconversion 来解决此问题。

标签: c gcc compiler-warnings suppress-warnings


【解决方案1】:

一天后没有任何答案让我接受,我将总结来自 cmets 的发现。

  • @Artyer 发现将变量转换为布尔值可以解决问题。这解决了战术问题,但没有解决更普遍的问题(例如z &amp; 0xf)。

    num->b = (5U << 1) | (_Bool)(x & 1);
    
  • @M.M 独立发现了我认为会产生相同效果的结果(转换为布尔值)。使用!! 可以解决问题。同样,这解决了战术问题,但没有解决更普遍的问题(例如z &amp; 0xf)。

    num->b = (5U << 1) | !!(x & 1);
    
  • 我在研究上述解决方案时发现,将表达式的“常量”端存储到变量中通常可以解决问题。

    unsigned int z = 5U;
    num->b = (z << 1) | (x & 1);
    
  • @yugr 认为这是一个错误。 Bug 95213 使用 gcc 打开以跟踪此问题。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2022-01-24
    • 1970-01-01
    • 1970-01-01
    • 2010-12-16
    • 2015-12-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多