简体   繁体   中英

GCC conversion warning when assigning to a bitfield

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?

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 (unsigned)b.flag | c.flag is strictly equivalent to (unsigned)b.flag | (unsigned)c.flag (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 .

After one year I revised the issue:

Just tested again with different compiler versions. When I first ran into this bug (now I am quite sure, I am allowed to call it a bug), I 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; a.flag = (unsigned)b.flag | c.flag; .

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM