Conversion error when accessing bits to set a bit field
Asked Answered
W

2

13

We are using bit fields to represent elements of a register read from a device.

#include <cstdint>

struct Register {
  uint8_t field : 1;
};

int main() {
  uint8_t byte{0}; // Read from a device
  Register r;
  r.field = (byte >> 5) & 0x1; // access bit 5
  r.field = (byte >> 7) & 0x1; // access bit 7, warns
}

We are also using the flag -Werror=conversion. For some reason, accessing bit 0 through 6 compiles without warning. However, accessing bit 7 warns for the conversion error: conversion from 'unsigned char' to 'unsigned char:1' may change value [-Werror=conversion].

Any ideas why this might be? Or how to right it in a way that will not warn of a conversion error?

Example here, https://godbolt.org/z/Ghd5ndnKd

Waken answered 11/7 at 13:25 Comment(6)
You told the compiler that you'd like narrowing conversion warnings and that's what it gave you. If you don't like it, get rid of -Wconversion, it was always unreliable and prone to false positives.Stemma
What if byte is a wider type when you select a bit from it?Performing
Potential duplicate of Son of GCC conversion warning when assigning to a bitfield. Most likely a compiler bug, int shift = 7; r.field = (byte >> shift) & 0x1; compilesBoiling
bitfields probably don't do what you think they do. They do not model addressable bits, but only create a variable that behaves as if it had N bits. Further the way bitfields behave is compiler specific. My advice, don't use them and do all your bit arithmetic manually (Mollusc
@PepijnKramer OP is actually using the bit-field without relying on any underlying representation. Their usage is completely portable.Hallowmas
r.field = ~byte & 128 ? 0 : 1; compiles (it even gives the expected code) but r.field = byte & 128 ? 1 : 0; does not...Kilt
E
9

It's indeed odd that you are getting 1 warning instead of 2 or 0.

Particularly suspicious wording conversion from 'unsigned char', because your (byte >> 7) & 0x1 has type int.

But since you're asking how to remove the warning, cast the value to a bool.

r.field = ((byte >> 7) & 0x1) != 0; // access bit 7

or

r.field = bool((byte >> 7) & 0x1); // access bit 7
Epiboly answered 11/7 at 13:41 Comment(3)
Thus demonstrating that dodging warnings on code whose meaning is well defined is often counter-productive. <g> Yes, these work, but both are misleading and inelegant. Nevertheless, +1.Faraway
perhaps add a comment along the line of // convert to bool to silence -Werror=conversionHackett
Somehow this actually generates better code at -O0.Kilt
S
1

It's a diagnostic bug. You can of course work around it, but rather than recognizing the bad diagnostics message, I suggest that you suppress it:

// Suppress error:
// "conversion from 'unsigned char' to 'unsigned char:1' may change value"
#pragma GCC diagnostic ignored "-Wconversion"  
  r.field = (byte >> 7) & 0x1;
#pragma GCC diagnostic pop
Strachey answered 1/8 at 14:42 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.