• AVR Freaks

Helpful ReplyHot!Bit Field / Struct / Union

Page: 12 > Showing page 1 of 2
Author
morbak
Starting Member
  • Total Posts : 49
  • Reward points : 0
  • Joined: 2008/08/12 06:08:56
  • Location: 0
  • Status: offline
2019/05/24 03:00:08 (permalink)
0

Bit Field / Struct / Union

Hi,
 
I've an issue into my code.
I want to create an union/struct on 4 bytes and have acces into bit filed. here's my struct declaration in .h:
typedef union _CAN_MESSAGE_ID 
{
 unsigned long ID; /
 struct
 {
  unsigned char BYTE_1;
  unsigned char BYTE_2;
  unsigned char BYTE_3;
  unsigned char BYTE_4;
 } BYTES;
 struct
 {
  int NuPe :8;
         int TyPe :4;
         int Cmde :5;
         int NuPd :8;
         int TyPd :4;
         int Empty:3;
 } PROTOCOLE ;
} CAN_MESSAGE_ID;

 
in main.c :
CAN_MESSAGE_ID entete_TX;

    entete_TX.PROTOCOLE.NuPe=1;
    entete_TX.PROTOCOLE.TyPe=2;
    entete_TX.PROTOCOLE.Cmde=3;
    entete_TX.PROTOCOLE.NuPd=4;
    entete_TX.PROTOCOLE.TyPd=5;

 
But when i fill all filed, field bit's length isn't respected but fill all bytes independently like :

 
and the entete_TX.ID isn't correct, it should be like that : 0001010 00001000 00110010 00000001 [0x0A083201]
 
Any ideas? 

Attached Image(s)

#1
pcbbc
Super Member
  • Total Posts : 992
  • Reward points : 0
  • Joined: 2014/03/27 07:04:41
  • Location: 0
  • Status: online
Re: Bit Field / Struct / Union 2019/05/24 03:21:31 (permalink) ☄ Helpfulby morbak 2019/05/24 07:39:27
+1 (1)
I don't think bit fields are allowed to cross byte boundaries.  So...
int NuPe :8;
int TyPe :4;
int Cmde :5;    //Crosses boundary - will be byte aligned at start of next byte
int NuPd :8;    //Crosses boundary - will be byte aligned at start of next byte
int TyPd :4;
int Empty:3;

 
Edit:
MPLAB® XC8 C Compiler User’s Guide for PIC® MCU - Page 419 - Section C.11 - STRUCTURES, UNIONS, ENUMERATIONS, AND BIT FIELDS
ISO Standard: “Whether a bit-field can straddle a storage unit boundary (C90 6.5.2.1, C99 6.7.2.1).”
Implementation: A bit-field cannot straddle a storage unit. Any bit-field that would straddle a storage unit will be moved to the LSb position in a new storage unit.

post edited by pcbbc - 2019/05/24 03:26:19
#2
morbak
Starting Member
  • Total Posts : 49
  • Reward points : 0
  • Joined: 2008/08/12 06:08:56
  • Location: 0
  • Status: offline
Re: Bit Field / Struct / Union 2019/05/24 03:29:05 (permalink)
0
arggg... so how to do ?
#3
pcbbc
Super Member
  • Total Posts : 992
  • Reward points : 0
  • Joined: 2014/03/27 07:04:41
  • Location: 0
  • Status: online
Re: Bit Field / Struct / Union 2019/05/24 03:49:28 (permalink)
+2 (2)
Either pack/unpack the bits yourself, or define a macro to do the packing/unpacking for you.
 
Something like:
typedef union _CAN_MESSAGE_ID {
    uint32_t ID;
    struct
    {
        uint8_t BYTE_1;
        uint8_t BYTE_2;
        uint8_t BYTE_3;
        uint8_t BYTE_4;
    } BYTES;
    struct
    {
        uint8_t NuPe    :8;
        uint8_t TyPe    :4;
        uint8_t Cmde_lo :4;
        uint8_t Cmde_hi :1;
        uint8_t NuPd_lo :7;
        uint8_t NuPd_hi :1;
        uint8_t TyPd    :4;
        uint8_t Empty   :3;
    } PROTOCOL;
} CAN_MESSAGE_ID;
 
#define GET_Cmde(x) ((x.PROTOCOL.Cmde_lo) | ((x.PROTOCOL.Cmde_hi) << 4))
#define GET_NuPd(x) ((x.PROTOCOL.NuPd_lo) | ((x.PROTOCOL.NuPd_hi) << 7))

#define SET_Cmde(x,v) x.PROTOCOL.Cmde_lo = v; x.PROTOCOL.Cmde_hi = v >> 4;
#define SET_NuPd(x,v) x.PROTOCOL.NuPd_lo = v; x.PROTOCOL.NuPd_hi = v >> 7;

I don't claim it's correct or pretty.
 
#4
LdB_ECM
Junior Member
  • Total Posts : 56
  • Reward points : 0
  • Joined: 2019/04/16 22:01:25
  • Location: 0
  • Status: offline
Re: Bit Field / Struct / Union 2019/05/24 07:47:11 (permalink)
0
That isn't bad but it needs packing instruction its not going to work, and I would use anonymous structs and unions to save some typing.

 
#pragma pack(1)   // Hard pack this record to byte boundaries
typedef union {
    uint32_t ID;
    struct
    {
        uint8_t BYTE_1;
        uint8_t BYTE_2;
        uint8_t BYTE_3;
        uint8_t BYTE_4;
    };
    struct
    {
        uint8_t NuPe    :8;
        uint8_t TyPe    :4;
        uint8_t Cmde_lo :4;
        uint8_t Cmde_hi :1;
        uint8_t NuPd_lo :7;
        uint8_t NuPd_hi :1;
        uint8_t TyPd    :4;
        uint8_t Empty   :3;
    };
} CAN_MESSAGE_ID;
#pragma pack()
 

 
You can then just use the fields

 
    CAN_MESSAGE_ID msg;
    msg.ID = 0;
    msg.NuPe = 5;
    msg.NuPd_hi = 1;
    msg.BYTE_1 = 0x45;
 

 
post edited by LdB_ECM - 2019/05/24 07:48:12
#5
mlp
boots too small
  • Total Posts : 749
  • Reward points : 0
  • Joined: 2012/09/10 15:12:07
  • Location: previously Microchip XC8 team
  • Status: offline
Re: Bit Field / Struct / Union 2019/05/24 15:52:00 (permalink)
0
The base type of a bitfield should be int (or unsigned int).
 
LdB_ECM

    struct  {
        uint8_t NuPe    :8;
        uint8_t TyPe    :4;
        uint8_t Cmde_lo :4;
        uint8_t Cmde_hi :1;
        uint8_t NuPd_lo :7;
        uint8_t NuPd_hi :1;
        uint8_t TyPd    :4;
        uint8_t Empty   :3;
    };


should be

    struct {
        unsigned NuPe    :8;
        unsigned TyPe    :4;
        unsigned Cmde_lo :4;
        unsigned Cmde_hi :1;
        unsigned NuPd_lo :7;
        unsigned NuPd_hi :1;
        unsigned TyPd    :4;
        unsigned Empty   :3;
    };

 
post edited by mlp - 2019/05/24 15:53:10

Mark (this opinion available for hire)
#6
LdB_ECM
Junior Member
  • Total Posts : 56
  • Reward points : 0
  • Joined: 2019/04/16 22:01:25
  • Location: 0
  • Status: offline
Re: Bit Field / Struct / Union 2019/05/24 22:09:31 (permalink)
-1 (1)
Don't do that it won't pack properly 
The version of GCC pic is using is not fully C11 compliant and it follows the old MSC bitfield pack of what it does.
To fix it then you have to use  -mno-ms-bitfields
 
To make it more annoying you don't have STATIC_ASSERT (because it isn't C11 compliant) to compile time check the size.
 
What is posted is correct on a fully C11 compliant compiler but not currently on the PIC compiler ... you have been warned.
 
One of my plays this weekend is to see why the compiler can't be updated to at least GCC6 or 7 :-)
post edited by LdB_ECM - 2019/05/24 22:20:19
#7
oliverb
Super Member
  • Total Posts : 163
  • Reward points : 0
  • Joined: 2009/02/16 13:12:38
  • Location: 0
  • Status: offline
Re: Bit Field / Struct / Union 2019/05/25 00:48:23 (permalink)
0
You're asking about XC8 not XC32?
I'm no authority on bit fields, but I'd try looking up how the PIC SFR definitions are written.
 
#8
Hen
Starting Member
  • Total Posts : 29
  • Reward points : 0
  • Joined: 2018/10/24 04:01:44
  • Location: 0
  • Status: offline
Re: Bit Field / Struct / Union 2019/05/25 04:17:16 (permalink)
0
I don't see the problem, but then again I'm not into reading C/C++ standards till my eyes bleeds.
 
I consider PIC1X platform a 8-bit word (data) controller and therefore bits resides *atomically* in 8-bit granularity.
 
To cope with other, wider or misaligned, bit-fields I'd go the pcbbc route, preferably using macros to get better readability where it matters.
 
#9
CiccioB
Starting Member
  • Total Posts : 50
  • Reward points : 0
  • Joined: 2013/12/11 05:32:50
  • Location: 0
  • Status: offline
Re: Bit Field / Struct / Union 2019/05/25 04:55:33 (permalink)
0
I think the problem is only in the order those bitfields are declared, as you can see the value is correctly stored in them.
Try this:

 
struct {
unsigned int Empty:3;
unsigned int TyPd :4;
unsigned int NuPd :8;
unsigned int Cmde :5;
unsigned int TyPe :4;
unsigned int NuPe :8;
};

 
CAN bus is a big endian protocol format, but PIC is little endian so it just enumerates the bits in the reverse order as you would expect them. It's a thing I have already seen in other little endian micros with respect to big endian ones.
post edited by CiccioB - 2019/05/25 04:58:23
#10
LdB_ECM
Junior Member
  • Total Posts : 56
  • Reward points : 0
  • Joined: 2019/04/16 22:01:25
  • Location: 0
  • Status: offline
Re: Bit Field / Struct / Union 2019/05/25 07:58:42 (permalink)
0
The issue is unsigned is a size of determine by the compiler for the bitfield pack, it is not a standard.
Is size of int on XC8 16bits?  .... If it is the record above will fail.
It will also fail for compilers with 8 bit and 24bit ints
 
Let me explain why, a bitfield can't cross the base size. So on the above Empty + TyPd + NuPd = 15bits
So Cmde is actually asking to be the high bit in 1 uint16_t and 4 bits at the bottom of of the next uint16_t
 
The compiler goes nope that can't happen and so it leaves you 1 bit unused in the uint16_t and then starts Cmde on the next uint16_t. The net result is that record will expand to 6 bytes
unsigned integer (16bits) number one will be Empty, TyPd, NuPd ... 15 bits used
unsigned integer (16 bits) number two will be Cmde, TyPe ... 9 bits used
unsigned integer (16bits) number 3 will be NuPe  8 bits used.
 
So as written the only compiler that will actually give you 4 bytes and 32 bits is on a compiler with 32bit ints.
 
Now on the C11 standard they have added wording
[If a series of bit fields does not add up to the size of an int, padding can take place. The amount of padding is determined by the alignment characteristics of the members of the structure. In some instances, bit fields can cross word boundaries.

So on C11 the packing size NOT the size of unsigned int determines how it packs and it can allow bitfields to cross word boundaries. So you can simply put #pragma pack(4) above that and it will correctly pack on even a 16 or 24 bit int compiler.
 
So when you write unsigned on a C11 bitfield you are referring to the current packing size as unsigned int ... not the normal unsigned int of the compiler.
post edited by LdB_ECM - 2019/05/25 08:00:34
#11
LdB_ECM
Junior Member
  • Total Posts : 56
  • Reward points : 0
  • Joined: 2019/04/16 22:01:25
  • Location: 0
  • Status: offline
Re: Bit Field / Struct / Union 2019/05/25 08:40:54 (permalink)
0
I had trouble with this one on XC16 because it's unsigned int are 32 bits and not C11 compliant ... thus it will give you 8 byte structure not what was intended which was 6 bytes. I suspect it will be same on XC32 if someone wants to try it.
 
#pragma pack(2)   // Want 16 bit packing for structure
typedef struct {
    union {
        struct {
            unsigned _unused : 2;            // @0-1        Unused bits
            unsigned close : 1;                 // @2        close contour
            unsigned liftclose : 1;             // @3        Open contour ... close vertex in air
            unsigned bezongrid : 1;         // @4        Bezier on grid point (Both quad and cubic)
            unsigned quadbezoffgrid : 1;  // @5        Quad bezier off grid point
            unsigned cubicbezoffgrid : 1;  // @6        Cubic bezier off grid point
            unsigned joinedcontour : 1;    // @7        This contour joins to another contour
            unsigned criticalcorner : 1;      // @8        Critical corner flag
            unsigned _reserved : 7;          // @9-15    Reserved bits
        };
        uint16_t RawFlags16;                 //    Raw access to all 16 bits of flags
    };
    int16_t x;                                     // Vertex x co-ord
    int16_t y;                                     // Vertex y co-ord
} VECFONT_VERTEX2D;
#pragma pack()

If you want a 6 byte structure on XC16 you have to use uint16_t like this
#pragma pack(2)    // Want 16 bit packing for structure
typedef struct {
    union {
        struct {
            uint16_t _unused : 2;                // @0-1        Unused bits
            uint16_t close : 1;                    // @2        close contour
            uint16_t liftclose : 1;                // @3        Open contour ... close vertex in air
            uint16_t bezongrid : 1;                // @4        Bezier on grid point (Both quad and cubic)
            uint16_t quadbezoffgrid : 1;        // @5        Quad bezier off grid point
            uint16_t cubicbezoffgrid : 1;        // @6        Cubic bezier off grid point
            uint16_t joinedcontour : 1;            // @7        This contour joins to another contour
            uint16_t criticalcorner : 1;        // @8        Critical corner flag
            uint16_t _reserved : 7;                // @9-15    Reserved bits
        };
        uint16_t RawFlags16;                    //    Raw access to all 16 bits of flags
    };
    int16_t x;                                  // Vertex x co-ord
    int16_t y;                                  // Vertex y co-ord
} VECFONT_VERTEX2D;
#pragma pack()

post edited by LdB_ECM - 2019/05/25 08:42:56
#12
NKurzman
A Guy on the Net
  • Total Posts : 17341
  • Reward points : 0
  • Joined: 2008/01/16 19:33:48
  • Location: 0
  • Status: offline
Re: Bit Field / Struct / Union 2019/05/25 08:54:56 (permalink)
+1 (1)
“I had trouble with this one on XC16 because it's unsigned int are 32 bits “ XC16 is 16 bit ints not 32.
#13
mlp
boots too small
  • Total Posts : 749
  • Reward points : 0
  • Joined: 2012/09/10 15:12:07
  • Location: previously Microchip XC8 team
  • Status: offline
Re: Bit Field / Struct / Union 2019/05/26 17:20:47 (permalink)
+6 (6)
LdB_ECM
Don't do that it won't pack properly 
The version of GCC pic is using is not fully C11 compliant

Last time I checked, this was the XC8 forum.
Last time I checked, XC8 was not using any version of GCC at all.
Last time I checked, XC8 was not claiming C11 compliance.
Last time I checked, there was no code in this thread that requires C11 compliance.
Last time I checked, every C language standard since 1989 has left structure packing and bitfield order up to the implementer.
Last time I checked, every C language standard since 1989 has said bitfields should be declared as int or unsigned, regardless of the size of a machine word.
Last time I checked, the XC8 manual made it very clear that bitfields can't cross a byte boundary.
 
Did I forget to check anything?
 
One of my plays this weekend is to see why the compiler can't be updated to at least GCC6 or 7 :-)

I can save you the effort: because it's not based on GCCanything.
post edited by mlp - 2019/05/26 17:22:25

Mark (this opinion available for hire)
#14
qhb
Superb Member
  • Total Posts : 9998
  • Reward points : 0
  • Joined: 2016/06/05 14:55:32
  • Location: One step ahead...
  • Status: offline
Re: Bit Field / Struct / Union 2019/05/26 17:37:57 (permalink)
0
I think LdB_ECM is assuming that XC8, XC16 and XC32 all have the same base...
They appear to be talking about XC16 with the other stuff.
 

Nearly there...
#15
LdB_ECM
Junior Member
  • Total Posts : 56
  • Reward points : 0
  • Joined: 2019/04/16 22:01:25
  • Location: 0
  • Status: offline
Re: Bit Field / Struct / Union 2019/05/27 07:05:58 (permalink)
0
Yes sorry I don't use the XC8 haven't used a device that small in about 20 years. I wrongly assumed the XC8 was like it's big brothers. The objective was code portability and if the XC8 is back at C89 I wouldn't use it or the devices anyhow. 
 
So I will make sure I ignore the XC8 forum in future, sorry for trouble.
#16
mlp
boots too small
  • Total Posts : 749
  • Reward points : 0
  • Joined: 2012/09/10 15:12:07
  • Location: previously Microchip XC8 team
  • Status: offline
Re: Bit Field / Struct / Union 2019/05/27 12:24:02 (permalink)
+3 (3)
LdB_ECM
I wrongly assumed

I should have guessed your product knowledge was on a par with your understanding of the Standard(s).
 
if the XC8 is back at C89

It's not, as of 2.0.
But nothing in this discussion of bitfields so far has changed significantly since C89 anyway, so your objections have all been meaningless.
 

So I will make sure I ignore the XC8 forum in future, sorry for trouble.

Don't let the door hit you in the arse on the way out.
I wanted to say that so many times during the 5 years I was a Microchip employee.

Mark (this opinion available for hire)
#17
LdB_ECM
Junior Member
  • Total Posts : 56
  • Reward points : 0
  • Joined: 2019/04/16 22:01:25
  • Location: 0
  • Status: offline
Re: Bit Field / Struct / Union 2019/05/27 19:19:27 (permalink)
-1 (1)
Always love a keyboard thug and no one can make a mistake.
 
What mummy not treat you right ... seek help.
#18
Hen
Starting Member
  • Total Posts : 29
  • Reward points : 0
  • Joined: 2018/10/24 04:01:44
  • Location: 0
  • Status: offline
Re: Bit Field / Struct / Union 2019/05/27 21:06:34 (permalink)
+1 (1)
Portability is not a bad thing and I've put in lot effort towards it in my life but often reaslising getting less done and seldom reaping any benefits, maybe I'm doing it the wrong way...
 
BTW, the superior debater always receives the final whack.
#19
NKurzman
A Guy on the Net
  • Total Posts : 17341
  • Reward points : 0
  • Joined: 2008/01/16 19:33:48
  • Location: 0
  • Status: offline
Re: Bit Field / Struct / Union 2019/05/28 13:10:19 (permalink)
+1 (1)
As of 2.0 XC8 supports C99.  There is a reason Small chips do not move easily to C11.  That Standard committee assumes, like you there, are no small chips.
Not all Compilers are GCC.  But many are these days.
Not all people that disagree with you are Keyboard Thugs.  Some spent years writing the compiler in question and therefore know a great deal about it, and the C Standard in general.  Also note GCC is not always standards complaint.
#20
Page: 12 > Showing page 1 of 2
Jump to:
© 2019 APG vNext Commercial Version 4.5