Search code examples
cvariable-assignmentcompiler-warningscompiler-flagsnibble

Cast variable to nibble in struct


I face the following. I have a struct like this:

typedef struct 
{
    uint8 nibble_1 : 4;
    uint8 nibble_2 : 4;
    uint8 data_1;
    uint8 data_2;
    uint8 data_3;
} NibbleStruct;

Background information: It is a 32 bit message for CAN communication.

In the code I have the following:

...
NibbleStruct nibble_struct;
uint8 nibble_to_assign = 0U;
nibble_struct.nibble_1 = nibble_to_assign;
...

I need to retain the GCC (gnu99) flag -Werror=conversion but that gives the error message:

file_name.c error: conversion to 'unsigned char:4' from 'uint8' may alter its value [-Werror=conversion]|

I tried to cast with something like

...
nibble_struct.nibble_1 = (uint8:4) nibble_to_assign; // invalid code
...

and

...
nibble_struct.nibble_1 = (uint8) nibble_to_assign : 4; // invalid code
...

but was not surprised that this does not compile.

Is there any way to cast my variable nibble_to_assign to the nibble nibble_1 of the struct? Or to declare a nibble in the code outside a struct.


Solution

  • It is recommended to drop "garage standard" uint8 for ISO C standard uint8_t.

    There's various things to keep in mind here:

    • Bit-fields of character type/uint8_t is not supported by the C standard - this is a non-portable compiler extension.
    • As such, type conversions and promotions of non-standard bit-field members aren't covered by the C standard either.
    • -Wconversion is a shaky compiler option which is prone to false positives and misleading diagnostics. It is good to use for stress testing/code review but not something you should include in your normal build.

    The issue that -Wconversion whines about in this case is that can apparently not predict if the uint8_t value will fit inside a 4 bit bit-field.

    I was able to silence it by forcing an unsigned promotion to unsigned int:

    nibble_struct.nibble_1 = nibble_to_assign & 0xFu;
    

    But please note that neither structs nor bit-fields are particularly suitable or recommended for modelling hardware or data protocols. There may be padding bytes or padding bits inside the struct. If you insist on using the struct, you may have to write serialization/deserialization routines to avoid issues with padding. You may have to do this anyway to handle endianess, since CAN is most often (but not always) using big endian.