当分配到一个位域时,GCC转换之子警告。

问题描述 投票:2回答:1

我想解决的问题几乎和你一样。分配给位场时的GCC转换警告 只是所有的解决方案似乎都没有用。 和链接的问题一样,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;
}

看着它在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位,随机投射到无符号的int,以及几乎所有上述组合(例如,只是掩码,只是投射,投射到似乎任何相关的位置,等等)。 第一个num.b赋值可以用常量,但加入变量会把一切都搞乱。

我通过如下的实用程序解决了这个问题,但这并不是一个很满意的解决方案。

#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就能解决问题。 为什么一个常量和一个变量的组合会导致这个问题?

c gcc compiler-warnings suppress-warnings
1个回答
0
投票

一天后没有任何答案让我接受,我就把评论中的发现总结一下。

  • @Artyer发现,将变量投向布尔值就能解决问题。 这解决了战术问题,但并没有解决更普遍的问题(如 z & 0xf).

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

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

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

© www.soinside.com 2019 - 2024. All rights reserved.