GCC Conversion Warning When Assigning a Bit Field

Is there a way to suppress 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; } 

A warning

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

It seems that the two flags are expanded to int when they are connected to each other. I think it's really strange that casting either of the two flags to unsigned suppresses the warning.

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

Is this a compiler error or should it work this way?

+8
source share
3 answers

A year later, I revised the question:

Just tested again with different versions of the compiler. When I first encountered this error (no, I'm sure I'm allowed to call it an error), he already realized that the warning existed only in clang <3.1 and all versions of GCC at that time. A warning is still issued by all versions of GCC <5.

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

0
source

It seems that the two flags are expanded to int when they are connected to each other.

This is a whole advance and is defined in the strangely formulated section 6.3.1.1-2 of standard C99:

The following expressions can be used in an expression: int or unsigned int can be used:

...

- a bit field of the type _Bool, int, signed int or unsigned int. If int can represent all values โ€‹โ€‹of the original type, the value is equally converted to int; otherwise, it will be converted to unsigned int. They are called whole stocks. All other types do not change through whole promotions.

Firstly, the processor does not calculate directly from bit fields and may also not have instructions for calculating narrower integer types char and short . The C standard fixes this by having arithmetic operations defined only on int , unsigned int and wider integer types. If the standard says โ€œcan be usedโ€ above, he tries (poorly) to express that all are short types, and bit fields should be promoted to int or unsigned int before participating in arithmetic.

Secondly, all unsigned bit fields that are not wide enough to include values โ€‹โ€‹that cannot be represented as int advance to int . In other words, GCC behaves in accordance with the standard, pushing your unsigned bit field into a signed int , and adding an explicit cast, like you, seems like the best policy against bad surprises in the future (and against a warning).

I think it's really strange that casting either of the two flags to unsigned cancels the warning.

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

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

+7
source

The best way to clear this warning is to explicitly confirm that you don't need extra bits:

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

I am 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 .

I canโ€™t comment on why explicit casting to (unsigned) solves this problem if you posted. Weird at best, and I doubt you are lucky in other circumstances.

0
source

Source: https://habr.com/ru/post/974288/


All Articles