C89 has no real provision for initializing and passing unions as arguments directly. In C89 Unions can only be declared using variable or variable references and then must be initialized using the variable. However you then can pass and return these variables by value, so without using pointers.
Returned structs and unions need not fit into registers like normal return parameters. In this case the compiler does everything for you (on the stack), and if it is deeply optimizing and inlined, this usually does not involve much overhead (read: Carefully hand optimized C code can be faster, however often the optimizer does a fairly good job).
Below is example code.
With the utility functions create_GAIN_REG_st
and GAIN_REG_st_to_G_u
you can create the struct/union on the fly on the argument list to the call of your function, which is accepting these as parameter(s).
Please note that this only works for non-pointer-types this way, as pointer must point somewhere. If you use pointers, you need to malloc
/free
. But with returning the whole datatype you do not need that. One important thing is that you can get a pointer to the data created on the fly, but the data only lives during the call, as usual for variables on the stack - this can quickly lead to "use after free" or pointers aliased to re-used stack regions. (So always avoid pointers to structs/unions which are passed as arguments, which are returned or which are temporary variables.)
#define __inline__ /*if not using GCC*/
typedef struct {
uint8_t rdwr_u8: 1;
uint8_t not_used_u8: 3;
uint8_t address_u8: 4;
uint8_t reserved_u8: 8;
uint8_t data_u8: 8;
uint8_t padding_u8: 8;
} GAIN_REG_st;
typedef union {
GAIN_REG_st GAIN_st;
uint32_t G_32;
} G_u;
GAIN_REG_st __inline__
create_GAIN_REG_st(uint8_t rdwr, uint8_t address, uint8_t data)
{
GAIN_REG_st g = { 0 };
g.rdwr_u8 = rdwr;
g.address_u8 = address;
g.data_u8 = data;
return g;
}
G_u __inline__
GAIN_REG_st_to_G_u(GAIN_REG_st g)
{
G_u u = { 0 };
u.GAIN_st = g;
return u;
}
Now you can directly call your function spi
:
void
spi(G_u u)
{
if (u.GAIN_st.rdwr_u8)
{
/* implement rdwr_u8==1 here */
}
else
{
/* implement rdwr_u8==1 here */
}
}
int
main()
{
spi(GAIN_REG_st_to_G_u(create_GAIN_REG_st(1,19,255)));
return 0;
}
Of course you can flatten out the double call:
G_u __inline__
create_G_u_bits(uint8_t rdwr, uint8_t address, uint8_t data)
{
return GAIN_REG_st_to_G_u(create_GAIN_REG_st(rdwr, address, data));
}
int
main()
{
spi(create_G_u_bits(1,19,255));
return 0;
}
or you can create a specialized function:
void
spi_bits(uint8_t rdwr, uint8_t address, uint8_t data)
{
spi(GAIN_REG_st_to_G_u(create_GAIN_REG_st(rdwr, address, data)));
}
int
main()
{
spi_bits(1,19,255);
return 0;
}