Gcc: Accessing and initializing unions and bitfields within struct - c

I have a struct that consists of a union, a variable and a bitfield:
typedef struct router_client {
union {
QHsm *client;
void (*handler)(QSignal sig, QParam par);
};
uint8_t level;
struct {
uint8_t presence:2;
uint8_t is_hsm:1;
uint8_t is_handler:1;
};
} router_client_t;
What is the proper way to initialize it? I used to
router_client_t = {.client=(QHsm*)&qhsm_foo, level = l, \
.presence = p, .is_hsm = s, .is_handler = a}
But when switching toolchain from Code Red MCU tools to Cross GCC I started getting
unknown field 'client' specified in initializer
unknown field 'presence' specified in initializer
...
The point of the union is that I want to be able to assign values either to client or handler and let them share the same pointer.
I tried a few things and I know I can change the struct but I just wanted to know if there is a C99 way of initializing and accessing it.

This can work. I think that the trick is name of structs and union.
typedef union {
int *client;
void (*handler)(int sig, int par);
}union_t;
typedef struct {
uint8_t presence:2;
uint8_t is_hsm:1;
uint8_t is_handler:1;
}struct_t;
typedef struct router_client {
union_t test;
uint8_t level;
struct_t test2
} router_client_t;
void main()
{
int pippo;
router_client_t pippo2= {.test.client=(int*)&pippo, .level = 10, .test2.presence = 2, .test2.is_hsm = 1, .test2.is_handler = 1};
}
Or as you wrote:
#include <stdint.h>
typedef struct router_client {
union{
int *client;
void (*handler)(int sig, int par);
}union_t;
uint8_t level;
struct {
uint8_t presence:2;
uint8_t is_hsm:1;
uint8_t is_handler:1;
}struct_t;
} router_client_t;
void main()
{
int pippo;
router_client_t pippo2= {.union_t.client=(int*)&pippo, .level = 10, .struct_t.presence = 2, .struct_t.is_hsm = 1, .struct_t.is_handler = 1};
}

I see an unnamed struct and an unnamed union.
It is highly probably that the cross gcc compiler is not handling anonymous structs and unions with what ever the default standard is.
suggest adding an appropriate parameter to the compile, something like
'-std=c11'

Related

How to dereference member from struct in which the definition is hid from user?

Payload_Manager.h
typedef struct ATEIS_Payload_s* pATEIS_Payload;
Payload_Manager.c
#include "Payload_Manager.h"
struct __attribute__((__packed__))ATEIS_Payload_s //payload
{
uint32_t Addr;
uint16_t Cmd;
uint16_t Len;
uint8_t Data[];
};
DNM_Manager.h
#include "Payload_Manager.h"
typedef struct DNM_s* pDNM;
pDNM DNMManager_Ctor(pDNM this, pATEIS_Payload src);
DNM_Manager.c
#include "Payload_Manager.h"
struct DNM_s
{
uint32_t Addr;
uint32_t SerialNo;
uint32_t SubnetMask;
uint16_t Tick;
uint8_t Name[NAME_SIZE];
}DNMSet[SET_SIZE], DNMTemp;
pDNM DNMManager_Ctor(pDNM this, pATEIS_Payload src)
{
memcpy(this->Name, &src->Data[NAME], NAME_SIZE); //ptr to incomplete class type is not allowed
this->Addr = src->Addr; //ditto
this->SerialNo = *(uint32_t*)&src->Data[SN]; //ditto
this->SubnetMask = *(uint32_t*)&src->Data[SUBMASK]; //ditto
this->Tick = 0;
return this;
}
main.c
#include "Payload_Manager.h"
#include "DNM_Manager.h"
pDNM DNM_temp = NULL;
DNM_temp = DNMManager_New(); //get one DNM
DNM_temp = DNMManager_Ctor(DNM_temp, pl_p); //init DNM_temp by pl_p
The file DNM_Manager.c needs to know declaration of ATEIS_Payload_s, otherwise it cannot dereference it.
How can I do except that declare ATEIS_Payload_s again in DNM_Manager.c?
Thanks.
As Groo suggested, the implementer must offer functions to user to manipulate members. Here is a snippet from my code:
uint32_t PayloadManager_GetAddr(ATEIS_Payload_s* this)
{
return this->Addr;
}

Pointer in const C struct

Assuming that the following structures exist...
typedef struct MyFirstStruct
{
uint8_t someContent;
}
typedef struct MySecondStruct
{
MyFirstStruct* firstStructs;
uint8_t firstStructCount;
}
... and a function gets the following Parameter.
const MySecondStruct* const secondStruct
Is it allowed to change any value?
I am sure that this is not correct:
secondStruct->firstStructCount++.
But neither the Compiler nor PC-Lint complains about secondStruct->firstStructs->someContent++.
Is it allowed to do Change someContent because firstStructs is not const or is the behavior undefined?
Thanks!
The values of the nested struct(s) firstStructs can change as long as the pointer does not change. The constness of the pointer prevents the pointer value from changing, but the constness of the struct only means that its values must not change (i.e. the value of the pointer and the count).
You can modify the struct(s) pointed to by firstStructs arbitrarily without changing the pointer. You can also clearly see from the struct definition that this is legal, because firstStructs is a pointer to struct MyFirstStruct, not a pointer to const struct MyFirstStruct.
Here is an example to understand the principle without the const-pointer to const elements:
#include <stdio.h>
#include <stdlib.h>
typedef struct {
int x;
} Simple;
typedef struct {
Simple* s;
int scount;
} Nested;
int main()
{
Nested x;
x.scount = 10;
x.s = malloc(sizeof(Simple) * x.scount);
const Nested n = x;
for (int i = 0; i < n.scount; ++i)
{
n.s[i].x = i;
printf("%d\n", n.s[i].x);
}
}
It is OK and it was easy to check yourself:
typedef struct
{
uint8_t someContent;
} MyFirstStruct;
typedef struct
{
MyFirstStruct* firstStructs;
uint8_t firstStructCount;
}MySecondStruct;
MyFirstStruct fs;
MySecondStruct str = {.firstStructs = &fs};
const MySecondStruct* const secondStruct = &str;
int main()
{
secondStruct->firstStructs->someContent++;
}
but did not as the posted code was full of syntax errors.
You cant of course change the pointer itself:
This will give you errors:
typedef struct
{
uint8_t someContent;
} MyFirstStruct;
typedef struct
{
MyFirstStruct* firstStructs;
uint8_t firstStructCount;
}MySecondStruct;
MyFirstStruct fs[2];
MyFirstStruct ss;
MySecondStruct str = {.firstStructs = fs};
const MySecondStruct* const secondStruct = &str;
int main()
{
secondStruct->firstStructs++->someContent++;
secondStruct->firstStructs = &ss;
}

Error[Pe142]: expression must have pointer-to-object type

I'm coding c in IAR Embedded workbench IDE. I have the following in a header file.
typedef union {
uint8_t payload;
struct UBX_NAV_POSLLH nav_posllh;
struct UBX_NAV_STATUS nav_status;
struct UBX_NAV_DOP nav_dop;
struct UBX_NAV_SOL nav_sol;
struct UBX_NAV_VELNED nav_velned;
struct UBX_NAV_TIMEUTC nav_timeutc;
struct UBX_NAV_SVINFO nav_svinfo;
} UBXPayload;
struct UBXHeader {
uint8_t class;
uint8_t id;
uint16_t len;
uint8_t ck_a;
uint8_t ck_b;
};
struct UBXPacket {
struct UBXHeader header;
UBXPayload payload;
};
Here is my source file:
static char *c_buffer
void myinit( )
{
c_buffer= (char*)malloc(50);
}
int myfunc(uint8_t c, char *c_buffer)
{
static uint8_t rx_count = 0;
struct UBXPacket *ubx = (struct UBXPacket *)c_buffer;
for(int i=0; i<3; i++){
ubx->payload.payload[rx_count] = c; /* Error[Pe142]: expression must have pointer- to-object type */
rx_count++;
}
}
void main( )
{
char mychar = 'h';
myinit( );
myfunc(mychar, c_buffer);
}
The same union is defined as follows in another code sample written to be compiled with ARM GCC compiler. It compiles well & works well.
typedef union {
uint8_t payload[0]; /* here [0] is placed */
struct UBX_NAV_POSLLH nav_posllh;
struct UBX_NAV_STATUS nav_status;
struct UBX_NAV_DOP nav_dop;
struct UBX_NAV_SOL nav_sol;
struct UBX_NAV_VELNED nav_velned;
struct UBX_NAV_TIMEUTC nav_timeutc;
struct UBX_NAV_SVINFO nav_svinfo;
} UBXPayload;
But in IAR C compiler giving error. Any suggestions please ?
I do not understand the following line
struct UBXPacket *ubx = (struct UBXPacket *)c_buffer;
In the UBXPayload union the payload member is a single character, but you use it as an array. And when you make it an array you make it an array of size zero so all writes to the array will be out of bounds, leading to undefined behavior (so it's not working so well as you think it does).

C accessing array correctly

os-sim.h
typedef enum {
PROCESS_NEW = 0,
PROCESS_READY,
PROCESS_RUNNING,
PROCESS_WAITING,
PROCESS_TERMINATED
} process_state_t;
typedef struct _pcb_t {
const unsigned int pid;
const char *name;
const unsigned int static_priority;
process_state_t state; <<---Trying to access this
op_t *pc;
struct _pcb_t *next;
} pcb_t;
file1.c
static pcb_t **current;
extern void yield(unsigned int cpu_id)
{
/* FIX ME */
while (1)
{
pthread_mutex_lock(&current_mutex);
current[cpu_id].state = PROCESS_WAITING; ///<-------ERROR HERE
pthread_mutex_unlock(&current_mutex);
break;
}
schedule(cpu_id);
}
in main method():
current = malloc(sizeof(pcb_t*) * 10);
I have error in this line current[cpu_id].state = PROCESS_WAITING;
error: request for member ‘state’ in something not a structure or union
What does this error mean?
Is this not the right way to access current array which holds pcb_t?
If so, how do i access the current array? and state field?
You're likely looking for:
current[cpu_id]->state = PROCESS_WAITING;
The type of current is pcb_t **. So the type of current[cpu_id] is pcb_t *.

Casting struct into int

Is there a clean way of casting a struct into an uint64_t or any other int, given that struct in <= to the sizeof int?
The only thing I can think of is only an 'ok' solution - to use unions. However I have never been fond of them.
Let me add a code snippet to clarify:
typedef struct {
uint8_t field: 5;
uint8_t field2: 4;
/* and so on... */
}some_struct_t;
some_struct_t some_struct;
//init struct here
uint32_t register;
Now how do i cast some_struct to capture its bits order in uint32_t register.
Hope that makes it a bit clearer.
I've just hit the same problem, and I solved it with a union like this:
typedef union {
struct {
uint8_t field: 5;
uint8_t field2: 4;
/* and so on... */
} fields;
uint32_t bits;
} some_struct_t;
/* cast from uint32_t x */
some_struct_t mystruct = { .bits = x };
/* cast to uint32_t */
uint32_t x = mystruct.bits;
HTH,
Alex
A non-portable solution:
struct smallst {
int a;
char b;
};
void make_uint64_t(struct smallst *ps, uint64_t *pi) {
memcpy(pi, ps, sizeof(struct smallst));
}
You may face problems if you, for example, pack the struct on a little-endian machine and unpack it on a big-endian machine.
you can use pointers and it will be easy
for example:
struct s {
int a:8;
int b:4;
int c:4;
int d:8;
int e:8; }* st;
st->b = 0x8;
st->c = 1;
int *struct_as_int = st;
hope it helps
You can cast object's pointer to desired type and then resolve it. I assume it can be a little bit slower than using unions or something else. But this does not require additional actions and can be used in place.
Short answer:
*(uint16_t *)&my_struct
Example:
#include <stdio.h>
#include <stdint.h>
typedef struct {
uint8_t field1;
uint8_t field2;
} MyStruct;
int main() {
MyStruct my_struct = {0xFA, 0x7D};
uint16_t num_my_struct = *(uint16_t *)&my_struct;
printf("%X \n", num_my_struct); // 7DFA
return 0;
}

Resources