Why is this UNION like a struct? - c

I came across some code (it's in a library from Microchip) which has a union.
All was good, until I saw it assigned values to different members of the union right after each other. My immediate thought was "They are over writing the same location..."
Then I decided to do a test. By every measure I thought I understood, this union should be one byte (8 bits). But it's not... it's 4 bytes.
#pragma pack(1)
typedef union _STATUS
{
BYTE Val;
struct {
unsigned BC8 : 1;
unsigned BC9 : 1;
unsigned BSTALL : 1;
unsigned DTSEN : 1;
unsigned INCDIS : 1;
unsigned KEN : 1;
unsigned DTS : 1;
unsigned UOWN : 1;
};
struct {
unsigned BC8 : 1;
unsigned BC9 : 1;
unsigned PID0 : 1;
unsigned PID1 : 1;
unsigned PID2 : 1;
unsigned PID3 : 1;
unsigned : 1;
unsigned UOWN : 1;
};
struct {
unsigned : 2;
unsigned PID : 4;
unsigned : 2;
};
} STATUS;
void PrintIt() {
printf("Size of UNION is %d \n", sizeof(STATUS));
}
It should be the largest of any member, which each member is only 8 bits.
The code that caught my eye and made me investigate this is:
STAT.BC9 = 0;
STAT.BC8 = 0;
STAT.Val |= byteToSend;
Which the third line merges into the values from the first and second.
So I wanted to test it, it's coming out as 4 bytes, not one. I even tested it in a few different compilers (hence the #pragma usage for MS Visual C).
Each member is exactly 8 bits, and the last two struct overlap to place the PID values in the same memory location. And yet this is 4 bytes every way I use a compiler to evaluate it.
Is there something in the behavior of adding structs to unions?
Any explanation is appreciated.

While not explicitly specified in the C standard, bitfield will typically occupy a unit corresponding to the base type they are declared with.
In this case all of the bitfields are declared as unsigned. This type is probably 4 bytes on your system so the bitfields occupy a unit of that type.
If you change the types of the fields to unsigned char or uint8_t they should take up only one byte. Note that this assumes your compiler allows using these types for bitfields, although most do.

C has the concept of implicit type. So unsigned will declare an unsigned int. But it gets weirder. The same goes if you only use const or static/auto.
const x = 5; // Declares a const int variable
static x; // Declares a static int variable
const static unsigned x = 5; // Declares a const static unsigned int variable
What you want is an unsigned char.
It should be the largest of any member, which each member is only 8 bits.
It should be at least that size. Nothing prevents it from being bigger.

It will not compile as you have duplicate member names in anonymous structures.
You do need to pack it if you use 8 bits type for your bitfields.
typedef union
{
unsigned char Val;
struct {
unsigned char BC8 : 1;
unsigned char BC9 : 1;
unsigned char BSTALL : 1;
unsigned char DTSEN : 1;
unsigned char INCDIS : 1;
unsigned char KEN : 1;
unsigned char DTS : 1;
unsigned char UOWN : 1;
};
struct {
unsigned char BC81 : 1;
unsigned char BC91 : 1;
unsigned char PID0 : 1;
unsigned char PID1 : 1;
unsigned char PID2 : 1;
unsigned char PID3 : 1;
unsigned char : 1;
unsigned char UOWN1 : 1;
};
struct {
unsigned char : 2;
unsigned char PID : 4;
unsigned char : 2;
};
} STATUS;
int main(void) {
printf("Size of UNION is %d \n", (int)sizeof(STATUS));
}
https://godbolt.org/z/zsfhnGeWd
Remember that some compilers will pack to the type you specify (chibicc for example).

While dbush was answering, I was adding my own answer as well, after digging deeper.
I would describe it as:
The "unsigned" implies an "int" So you are defining the first 8 bits of an integer storage.
typedef union _STATUS {
BYTE Val;
struct {
unsigned char BC8 : 1;
unsigned char BC9 : 1;
unsigned char BSTALL : 1;
unsigned char DTSEN : 1;
unsigned char INCDIS : 1;
....
} STATUS;
When limiting the size to unsigned char, the union is now actually 1 byte.

Related

Clear just bit field members of a struct?

I have a struct like the following:
struct Foo {
unsigned int id;
unsigned int flag_1 : 1;
unsigned int flag_2 : 1;
unsigned int flag_3 : 1;
// Some arbitrary number of further flags. Code is
// automatically generated and number will vary.
// Notably, it may be more than an int's worth.
int some_data;
float some_more_data;
// ...
};
From time to time, I need to reset all the flags to zero while preserving the rest of the struct. One way is obviously to set each flag to 0 individually, but it feels like there ought to be a way to do it in one fell swoop. Is that possible?
(Note that I am open to not using bit fields, but this is code that will sometimes run on memory-contrained systems, so the memory savings are very appealing.)
Edit:
There is a similar question here: Reset all bits in a c bitfield
However, the struct in that question is entirely bitfields. I cannot simply memset the entire struct to zero here, and the other answer involving unions is not guaranteed to work, especially if there are more than an int's worth of flags.
Just use a separate struct for the flags:
struct Foo_flags {
unsigned int flag_1 : 1;
unsigned int flag_2 : 1;
unsigned int flag_3 : 1;
// ...
};
struct Foo {
unsigned int id;
struct Foo_flags flags;
int some_data;
float some_more_data;
// ...
};
Or even a simpler nested struct:
struct Foo {
unsigned int id;
struct {
unsigned int flag_1 : 1;
unsigned int flag_2 : 1;
unsigned int flag_3 : 1;
// ...
} flags;
int some_data;
float some_more_data;
// ...
};
Then, later in your code:
struct Foo x;
// ...
x.flags.flag_1 = 1;
// ...
memset(&x.flags, 0, sizeof(x.flags));
With some minor adjustments, you can use the offsetof macro to find the beginning and end of the "flag" data within the structure, then use memset to clear the relevant memory. (Note that you cannot use offsetof directly on bitfields, hence the addition of the flag_beg member!)
Here's a working example:
#include <stdio.h>
#include <stddef.h> // defines offsetof
#include <string.h> // declares memset
struct Foo {
unsigned int id;
unsigned int flag_beg; // Could be unsigned char to save space
unsigned int flag_1 : 1;
unsigned int flag_2 : 1;
unsigned int flag_3 : 1;
unsigned int flag_end; // Could be unsigned char to save space
// Some arbitrary number of further flags. Code is
// automatically generated and number will vary.
// Notably, it may be more than an int's worth.
int some_data;
float some_more_data;
// ...
};
#define FBEG (offsetof(struct Foo, flag_beg))
#define FEND (offsetof(struct Foo, flag_end))
int main()
{
struct Foo f;
f.id = 3; f.flag_1 = 1; f.flag_2 = 0; f.flag_3 = 1;
f.some_data = 33; f.some_more_data = 16.2f;
printf("%u %u %u %u %d %f\n", f.id, f.flag_1, f.flag_2, f.flag_3, f.some_data, f.some_more_data);
memset((char*)(&f) + FBEG, 0, FEND - FBEG);
printf("%u %u %u %u %d %f\n", f.id, f.flag_1, f.flag_2, f.flag_3, f.some_data, f.some_more_data);
return 0;
}

Can a bit field structure be instantiated as an immediate?

Suppose I have the following (made up) definition:
typedef union {
struct {
unsigned int red: 3;
unsigned int grn: 3;
unsigned int blu: 2;
} bits;
uint8_t reg;
} color_t;
I know I can use this to initialize a variable that gets passed to a function, such as :
color_t white = {.red = 0x7, .grn = 0x7, .blu = 0x3};
printf("color is %x\n", white.reg);
... but in standard C, is it possible to instantiate a color_t as an immediate for passing as an argument without assigning it first to a variable?
[I discovered that yes, it's possible, so I'm answering my own question. But I cannot promise that this is portable C.]
Yes, it's possible. And the syntax more or less what you'd expect. Here's a complete example:
#include <stdio.h>
#include <stdint.h>
typedef union {
struct {
unsigned int red: 3;
unsigned int grn: 3;
unsigned int blu: 2;
} bits;
uint8_t reg;
} color_t;
int main() {
// initializing a variable
color_t white = {.bits={.red=0x7, .grn=0x7, .blu=0x3}};
printf("color1 is %x\n", white.reg);
// passing as an immediate argument
printf("color2 is %x\n", (color_t){.bits={.red=0x7, .grn=0x7, .blu=0x3}}.reg);
return 0;
}

C union pointer to array

I have an array of unsigned 16-bit integers:
static uint16_t dataArray[7];
The bits of the 7th element of the array represents some kind of status. I want to get and set the values of this status in an easy way, without bit shifting and without having to copy a new value to the array every time the status changes. So I created a union with a struct, and a pointer:
typedef struct {
unsigned statusCode : 4;
unsigned errorCode : 4;
unsigned outputEnabled : 1;
unsigned currentClip : 1;
unsigned : 6;
} SupplyStruct_t;
typedef union {
SupplyStruct_t s;
uint16_t value;
} SupplyStatus_t;
static SupplyStatus_t * status;
My initialisation routine wants the status pointer to point to the 7th element of the array, so I tried:
status = &(dataArray[6]);
Although this works, I get a warning: assignment from incompatible pointer type
Is there a better way to do this? I cannot change the array, but I am free to change the structure, the union or the pointer to the array..
Change unsigned to uint16_t
why? - test the difference:
https://ideone.com/uHLzpV
#include <stdio.h>
#include <stdint.h>
typedef struct {
uint16_t statusCode : 4;
unsigned errorCode : 4;
unsigned outputEnabled : 1;
unsigned currentClip : 1;
unsigned : 6;
} SupplyStruct_t;
typedef struct {
uint16_t statusCode : 4;
uint16_t errorCode : 4;
uint16_t outputEnabled : 1;
uint16_t currentClip : 1;
uint16_t : 6;
} SupplyStruct_t1;
typedef union {
SupplyStruct_t s;
uint16_t value;
} SupplyStatus_t;
typedef union {
SupplyStruct_t1 s;
uint16_t value;
} SupplyStatus_t1;
int main(void) {
printf("%zu %zu\n", sizeof(SupplyStatus_t), sizeof(SupplyStatus_t1));
return 0;
}
The most correct way is to declare the table as table of structs.
If not :
If you want too work on the bitfields you do not actually have to declare the pointer.
static SupplyStatus_t status;
status.value = dataArray[6];
and it is almost portable and safe way
you can also cast it explicitly
The warning says that uint16_t* is not compatible with SupplyStatus_t*.
If you want to get rid of this warning, cast it to SupplyStatus_t*:
status = (SupplyStatus_t*)&(dataArray[6]);
I also would put the union and struct together:
typedef union
{
struct
{
unsigned statusCode : 4;
unsigned errorCode : 4;
unsigned outputEnabled : 1;
unsigned currentClip :1;
unsigned unused : 6;
} s;
uint16_t value;
} SupplyStatus_t;

Define a structure that contains a data array and some pointers to the same data array areas

I want to define a structure that contains a data array and some pointers to the same data array. So I defined the structure and then I initialize the pointer like this:
typedef struct {
unsigned char data[MAX_PACKET_DATA];
unsigned char* sector1;
unsigned char* sector2;
unsigned char* sector3;
} Packet;
[...]
NGSCTransmittingDataPacket packet
[...]
packet->sector1 = packet.data + SECTOR1_OFFSET;
packet->sector2 = packet.data + SECTOR2_OFFSET;
packet->sector2 = packet.data + SECTOR3_OFFSET;
Can I initialize the pointer directly inside the typedef struct definition? If I write
typedef struct {
unsigned char data[MAX_PACKET_DATA];
unsigned char* sector1 = data + SECTOR1_OFFSET;
unsigned char* sector2 = data + SECTOR2_OFFSET;
unsigned char* sector3 = data + SECTOR3_OFFSET;
} Packet;
the compiler gives me error.
Any solution?
you cannot do that, C won't allow it. But in your example you could do that equivalent:
typedef struct {
unsigned char data[SECTOR1_OFFSET];
unsigned char sector1[SECTOR2_OFFSET-SECTOR1_OFFSET];
unsigned char sector2[SECTOR3_OFFSET-SECTOR2_OFFSET];
unsigned char sector3[MAX_PACKET_DATA-SECTOR3_OFFSET];
} Packet;
There's no padding since all members are char arrays.
You normally cannot go further SECTOR1_OFFSET-1 for an index of data, but there it would work (or create an union with a MAX_PACKET_DATA-length array if you want to make it cleaner, because some compilers could complain if you're accessing data with a bigger index)
Example with an union of 2 anonymous structures:
#include <stdio.h>
#define SECTOR1_OFFSET 20
#define SECTOR2_OFFSET 50
#define SECTOR3_OFFSET 80
#define MAX_PACKET_DATA 100
typedef union
{
struct
{
unsigned char sector0[SECTOR1_OFFSET];
unsigned char sector1[SECTOR2_OFFSET-SECTOR1_OFFSET];
unsigned char sector2[SECTOR3_OFFSET-SECTOR2_OFFSET];
unsigned char sector3[MAX_PACKET_DATA-SECTOR3_OFFSET];
};
struct
{
unsigned char data[MAX_PACKET_DATA];
};
} Packet;
int main()
{
Packet p;
p.data[SECTOR3_OFFSET] = 'a';
p.data[SECTOR3_OFFSET+1] = 'z';
p.data[SECTOR3_OFFSET+2] = '\0';
printf("sector 3 %s\n",p.sector3);
return 0;
}
result:
sector 3 az

Is it possible to access the different Structure with same members by using Macros or any other functionality at runtime?(Structure updated))

In this code contains two structures and their naming is different. Structure member naming is same but type is different. Is there any possibility to change the structure name at run time by using macros or other functionality.
typedef struct STag_ABCRegisters
{
unsigned long aaa;
unsigned long bbb;
unsigned long ccc;
unsigned long dddd;
}RegistersABC;
typedef struct STag_CDERegisters
{
unsigned short aaa;
unsigned short bbb;
unsigned short ccc;
unsigned short dddd;
}RegistersCDE;
main()
{
int type = 1;
if(type == 1)
{
RegistersABC->ccc = 10;
}
else
{
RegistersCDE->ccc = 10;
}
/* after some process again checking the type updating structure*/
type = 2;
if(type == 1)
{
RegistersABC->aaa = 10;
}
else
{
RegistersCDE->aaa = 10;
}
}
I need the help for following process
In the above code contains complexity of if else condition.
So is there any possibilities for select the structure at run time??.
See the below Pseudo code steps for your understanding
main()
{
char type = "ABC";
Registers//type//->aaa = 10; // Type of structure name should be replaced here
}
As I stated in my comment, structures are just the way memory is organized on the machine.
If both structures were compiled by the same compiler on the same machine (architecture / OS), their memory footprint will be the same and you can simply cast their pointer to one to a pointer of the other.
This, however, is not the best way to go about "inheritance" with C.
At the moment, you can have something like this:
struct STag_ABCRegisters
{
unsigned short aaa;
unsigned long bbb;
unsigned short ccc;
unsigned short dddd;
} RegistersABC;
struct STag_CDERegisters
{
unsigned short aaa;
unsigned long bbb;
unsigned short ccc;
unsigned short dddd;
} RegistersCDE;
main()
{
(struct STag_CDERegisters*) pdata = (struct STag_CDERegisters*)&RegistersABC;
data->ccc = 10;
data->aaa = 10;
}
It works, but it isn't beautiful.
If you need two of the same, the correct way would be:
struct STag_Registers
{
unsigned short aaa;
unsigned long bbb;
unsigned short ccc;
unsigned short dddd;
};
struct STag_Registers RegistersABC, RegistersCDE;
main()
{
struct STag_Registers * data = &RegistersABC;
data->ccc = 10;
data->aaa = 10;
}
If you need struct inheritance, then the "trick" is to have the "parent" placed at the head of the struct, so that the memory footprint is aligned.
struct STag_Registers
{
unsigned short aaa;
unsigned long bbb;
unsigned short ccc;
unsigned short dddd;
};
struct STag_RegistersExtended
{
struct STag_Registers parent;
// ... more types
};
This allows a pointer to struct STag_RegistersExtended to be cast as a pointer to struct STag_Registers, so that functions that accept a pointer to struct STag_Registers can also accept a pointer to struct STag_RegistersExtended.
Good luck with C.
EDIT (answering comment)
If you're writing for an embedded system and you have reserved (fixed) memory addresses for the data, you could go with something such as:
typedef struct {
unsigned short aaa;
unsigned long bbb;
unsigned short ccc;
unsigned short dddd;
} register_s;
#define PTR2REG(p) ((register_s *)(p))
#define REG_A PTR2REG(0x1000))
#define REG_B PTR2REG(0x9000))
inline void perform_work(register_s * reg)
{
reg->ccc = 10;
// ...
reg->aaa = 10;
}
main()
{
perform_work(REG_A);
perform_work(REG_B);
if(REG_A->aaa == 10) // should be true
printf("work was performed");
}
You should note that struct have a memory alignment and packing order. The compiler will add padding to the struct you defined in the question, due to the long's memory alignment requirements. You can read more about struct packing here.
If your embedded system requires an exact bit / byte match (and is free from padding requirements), you should tell the complier not to add any padding. This is often done using #pragma pack
EDIT 2
I'm not sure where the type in your question is derived from... but if you have a global variable with the address for the struct, you could go with:
typedef struct {
unsigned short aaa;
unsigned long bbb;
unsigned short ccc;
unsigned short dddd;
} register_s;
#define PTR2REG(p) ((register_s *)(p))
#define REG_A PTR2REG(0x1000))
#define REG_B PTR2REG(0x9000))
register_s * active_register = REG_A;
inline void perform_work(void)
{
active_register->ccc = 10;
// ... active_register might change
active_register->aaa = 10;
}
main()
{
perform_work();
}
This is from a C++ perspective, you really should be more careful with those language tags if this is not what you want
Since C++ does not have reflection, it's not possible to do what you want at runtime. There are workarounds though.
For example one workaround could be to have a common base-class for the common elements (which in your simple example seems to be all). The you could have an unordered map translating strings to pointers to your structure.
Example:
struct CommonBase
{
unsigned short aaa;
unsigned long bbb;
unsigned short ccc;
unsigned short dddd;
};
struct ABC : CommonBase {};
struct DEF : CommonBase {};
int main()
{
std::unordered_map<std::string, std::unique_ptr<CommonBase>> items = {
{ "ABC", new ABC },
{ "DEF", new DEF }
};
std::cout << "Select item to modify (ABC or DEF): ";
std::string input;
std::cin >> input;
items[input]->aaa = 12;
}
For members that are not common, that are unique for each respective structure, then you need to actually check like you do now and then downcast the pointer to the correct type.
For a C solution there is none really, except to manually check like you do now.
Dynamic languages like python have buildin metadata table for reflection, so we just build one for help. Now it looks much like a script language.
_Generic need C11 std to work.
some code copied from How to save the result of typeof?
// some code copied from https://stackoverflow.com/questions/42222379/how-to-save-the-result-of-typeof
// gcc -std=c11 typeid_of_test.c
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <stdint.h>
#include <string.h>
typedef struct STRU
{
int32_t aaa;
double bbb;
int ccc;
char dddd;
}STRU;
typedef struct Metainfo
{
int type;
char* name; //or hash
int offset;
}Metainfo;
enum {TYPE_UNKNOWN, TYPE_INT, TYPE_CHAR, TYPE_DOUBLE};
#define typeid_of(T) _Generic((T), int: TYPE_INT, long: TYPE_INT, char: TYPE_CHAR, double: TYPE_DOUBLE, default: 0)
#define META(ST_, M_) {typeid_of((__typeof__(((ST_ *)0)->M_))0), #ST_ "." #M_, offsetof(ST_, M_)}
/* { typeid, name, offset } */
Metainfo meta[]={
META(STRU, aaa),
META(STRU, bbb),
META(STRU, ccc),
META(STRU, dddd),
};
int set_by_name(char* member_name, char* value, void* p)
{
int offset=0, type=0;
for(int i=0; i<sizeof(meta)/sizeof(Metainfo); i++)
if(stricmp(member_name, meta[i].name)==0)
{
offset=meta[i].offset;
type = meta[i].type;
}
switch(type)
{
case TYPE_INT:
*(int*)((char*)p+offset) = atoi(value);
break;
case TYPE_CHAR:
*(char*)((char*)p+offset) = atoi(value);
break;
case TYPE_DOUBLE:
*(double*)((char*)p+offset) = atof(value);
break;
default:
return 0;
}
return 1;
}
int main(void)
{
for(int i=0; i<sizeof(meta)/sizeof(Metainfo); i++)
printf("type:%d, name: %s, offset: %d\n", meta[i].type, meta[i].name, meta[i].offset);
STRU b={0};
set_by_name("stru.bbb", "3.1415926", &b);
printf("stru.bbb == %f", b.bbb);
return 0;
}

Resources