GCC conversion warning when assigning to a bitfield

落花浮王杯 提交于 2020-12-05 05:01:01

问题


Is there any way to supress the warning generated by gcc in this code:

int main() {
    struct flagstruct {
        unsigned flag : 1;
    } a,b,c;

    a.flag = b.flag | c.flag;

    return a.flag;
}

The warning is

warning: conversion to 'unsigned char:1' from 'int' may alter its value [-Wconversion]

It looks like the the two flags are extended to int when ored together. What I think is really strange is that casting any of the two flags to unsigned supresses the warning.

a.flag = (unsigned)b.flag | c.flag;

Is this a compiler bug or is it supposed to work this way?


回答1:


It looks like the the two flags are extended to int when ored together.

This is integer promotion and it is defined in the strangely worded clause 6.3.1.1:2 of the C99 standard:

The following may be used in an expression wherever an int or unsigned int may be used:

— A bit-field of type _Bool, int, signed int, or unsigned int. If an int can represent all values of the original type, the value is converted to an int; otherwise, it is converted to an unsigned int. These are called the integer promotions. All other types are unchanged by the integer promotions.

First, the processor does not compute directly on bit-fields, and may also not have instructions to compute on the narrower integer types char and short. The C standard captures this by having arithmetic operations defined only on int, unsigned int and wider integer types. Where the standard says “may be used” above, it is trying (poorly) to express that all short types and bit-fields must be promoted to int or unsigned int before participating in arithmetic.

Second, all unsigned bit-fields that are not wide enough to include values that cannot be represented as int are promoted to int. In other words, GCC is behaving according to the standard by promoting your unsigned bit-field into a signed int, and adding an explicit cast, as you did, seems the best policy against bad surprises in the future (and against the warning).

What I think is really strange is that casting any of the two flags to unsigned supresses the warning.

Usual arithmetic conversions, another interesting concept in the C standard (6.3.1.8 in C99), have for consequence that if any of the two operands is explicitly converted to an unsigned int, then the other operand is also, implicitly this time, converted to unsigned int and the | operation is an unsigned int operation producing an unsigned int result.

In other words, (unsigned)b.flag | c.flag is strictly equivalent to (unsigned)b.flag | (unsigned)c.flag. In this case the compiler considers that there is no reason for to warn about the assignment, since the result of the computation is an unsigned int.




回答2:


After one year I revised the issue:

Just tested again with different compiler versions. When I first run into this bug (no I am quite sure, I am allowed to call it a bug), it already realized the warning existed only in clang < 3.1 and all GCC versions at that time. The warning is still produced by all GCC versions < 5.

Since there is no other way to silence the error, the only solution is to update to GCC > 5 or add the unsigned cast a.flag = (unsigned)b.flag | c.flag;.




回答3:


The best way to solve this warning is to explicitly acknowledge you do not need the excess bits:

a.flag = (b.flag | c.flag) & 0x00000001;

I'm currently using arm-none-eabi-gcc.exe (GNU Tools for ARM Embedded Processors) 5.4.1 20160609 (release) [ARM/embedded-5-branch revision 237715], and this is the only consistent way to get rid of them.

Can't comment on why explicit casting to (unsigned) solves this in the case you posted, though. Peculiar at best, and I doubt whether you will be as lucky under other circumstances, too.



来源:https://stackoverflow.com/questions/25480059/gcc-conversion-warning-when-assigning-to-a-bitfield

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!