此代码适用于DAC芯片的驱动程序。
我的下面有一个位域代表一个24位寄存器。所以我需要做的是填充位域并将其写在SPI上到芯片上。
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;
在我的初始化函数中,我创建了一个union,如下所示。
union{
GAIN_REG_st GAIN_st;
uint32_t G_32;
} G_u;
现在我需要将一个GAIN_REG_st位域传递给一个将填充它的函数。
一旦填充完毕,我就可以将位域分配给32位整数,并将该整数传递给低级函数,以便通过SPI进行写入。
如何在位于联合内部时将位域GAIN_REG_st传递给函数? (你能展示一个函数原型并调用)吗?
该函数如何访问位域的成员? (它会像G_u.GAIN_st.rdwr_u8 = 1
吗?)
答案 0 :(得分:7)
union G_u
the_union;
the_union.GAIN_st.address_u8 = 0x4;
function_call( &the_union );
void function_call( union G_u *the_union )
{
uint8
address;
address = the_union->GAIN_st.address_u8;
return;
}
你是说这个意思吗?它是一个联盟,为什么要通过一个内部成员?它不会有任何区别。它们都以相同的内存偏移量开始。
答案 1 :(得分:4)
标题是关于传递联盟,但问题是关于传递结构。您可以执行其中任一操作,只需相应地声明函数参数并传递成员或整个联合。
所有当前的答案都证明了通过引用传递,但是没有必要这样做,你可以通过副本传递,对于最终为32位值的结构或联合而言,这不是更昂贵并且在被调用中保存解除引用功能,因此可能更有效;
void fn( union G_u arg );
int main()
{
union G_u param;
...
fn( param );
}
或传递结构:
void fn( GAIN_REG_st arg );
int main()
{
GAIN_REG_st param;
...
fn( param );
}
请注意,您可以在结构中输入dede:
typedef union
{
GAIN_REG_st GAIN_st;
uint32_t G_32;
} G_u ;
那么第一个例子就是简单;
void fn( G_u arg );
int main()
{
G_u param;
...
fn( param );
}
传递struct或union之间的开销几乎肯定没有差别。这只是你选择公开内部表征知识的问题。
答案 2 :(得分:1)
原型:
int populateGainRegSt(GAIN_REG_st *st);
该函数可以使用->
运算符访问结构字段:
st->data_u8 = 1;
用法:
G_u g;
...
populateGainRegSt( &(g.GAIN_st));
答案 3 :(得分:0)
#include <stdint.h>
#include <stdio.h>
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;
union G_u
{
GAIN_REG_st GAIN_st;
uint32_t G_32;
};
static void foo (GAIN_REG_st *data)
{
printf ("%x %x %x\n",
data->rdwr_u8,
data->not_used_u8,
data->address_u8);
}
int main ()
{
union G_u udata;
udata.G_32 = 1986;
foo (&udata.GAIN_st);
return 0;
}
答案 4 :(得分:0)
C89没有直接初始化和传递联盟作为参数的实际规定。在C89中,只能使用变量或变量引用声明联合,然后必须使用变量初始化。但是,然后您可以按值传递和返回这些变量,因此不使用指针。
返回的结构和联合不需要像普通的返回参数那样适合寄存器。在这种情况下,编译器会为您(在堆栈上)执行所有操作,如果它经过深度优化和内联,则通常不需要太多开销(读取:仔细手动优化的C代码可以更快,但优化程序通常会做得相当干得好。)
以下是示例代码。
使用实用程序函数create_GAIN_REG_st
和GAIN_REG_st_to_G_u
,您可以在参数列表中动态创建struct / union以调用函数,该函数接受这些作为参数。< / p>
请注意,这仅适用于非指针类型,因为指针必须指向某处。如果您使用指针,则需要malloc
/ free
。但是返回整个数据类型你不需要它。一个重要的事情是,您可以获得指向动态创建的数据的指针,但数据仅在调用期间存在,就像堆栈中的变量一样 - 这可以很快导致&#34;免费使用&#34;或指针别名重用堆栈区域。 (所以总是避免指向作为参数传递的结构/联合的指针,它们被返回或者是临时变量。)
#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;
}
现在您可以直接调用您的函数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;
}
当然你可以完成双重调用:
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;
}
或者您可以创建一个专门的功能:
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;
}