如何将union作为参数传递给函数

时间:2011-04-18 13:33:13

标签: c embedded device-driver

此代码适用于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吗?)

5 个答案:

答案 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_stGAIN_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;
}