如何将联合作为参数传递给函数

发布于 2024-11-01 17:58:03 字数 904 浏览 4 评论 0原文

此代码适用于 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{
        GAIN_REG_st GAIN_st;
        uint32_t G_32;
    } G_u;

现在我需要将 GAIN_REG_st 位字段传递给将填充它的函数。

填充后,我可以将位字段分配给 32 位整数,并将该整数传递给低级函数以通过 SPI 进行写入。

当位域 GAIN_REG_st 位于联合内部时,如何将位域 GAIN_REG_st 传递给函数? (你能展示一个函数原型并调用)吗?

该函数如何访问位域的成员? (会像G_u.GAIN_st.rdwr_u8 = 1吗?)

This code is for a driver for a DAC chip.

I have a bitfield below which represents a 24-bit register. So what I need to do, is populate the bitfield and write it out over SPI to the chip.

    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;

In my initialisation function I create a union as below.

    union{
        GAIN_REG_st GAIN_st;
        uint32_t G_32;
    } G_u;

Now I need to pass a GAIN_REG_st bitfield to a function which will populate it.

Once it's populated I can assign the bitfield to a 32-bit integer and pass that integer to a low level function to write over SPI.

How do I pass the bitfield GAIN_REG_st to a function when it's inside a union? (Can you show a function prototype and call)?

How does the function access the bitfield's members? (would it be like G_u.GAIN_st.rdwr_u8 = 1?)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

最冷一天 2024-11-08 17:58:03
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;
}

你是这个意思吗?既然是工会,为什么要通过内部成员呢?这不会有任何区别。它们都以相同的内存偏移量开始。

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;
}

Do you mean this? it's a union, so why pass an internal member? it won't make any difference. They all start at the same memory offset.

策马西风 2024-11-08 17:58:03

标题是关于传递联合,但问题是关于传递结构。您可以执行任一操作,只需相应地声明函数参数并传递成员或整个联合。

当前的所有答案都演示了通过引用传递,但没有必要这样做,您可以通过复制传递,这对于最终是 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 );
}

请注意,您可以在拥有结构时键入定义联合:

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 );
}

几乎可以肯定,传递结构体或联合体之间的开销没有区别。这只是您选择在哪里公开内部表示知识的问题。

The title is about passing the union, but the question asks about passing structure. You can do either, you simply declare the function argument accordingly and pass either the member or the whole union.

All the current answers demonstrate passing by reference, but there is no need to do that, you can pass by copy, which for a struct or union that is ultimately a 32bit value is no more expensive and saves a dereferencing in the called function, so may be more efficient;

void fn( union G_u arg );

int main()
{
    union G_u param;
    ...
    fn( param );
}

or to pass the structure:

void fn( GAIN_REG_st arg );

int main()
{
    GAIN_REG_st param;
    ...
    fn( param );
}

Note that you could typedef the union as you have the struct:

typedef union 
{
    GAIN_REG_st GAIN_st;
    uint32_t    G_32;
} G_u ;

then the first example would be simply;

void fn( G_u arg );

int main()
{
    G_u param;
    ...
    fn( param );
}

There will almost certainly be no difference in overhead between passing the struct or the union. It is just a matter of where you choose to expose knowledge of the internal representation.

九局 2024-11-08 17:58:03

原型:

int populateGainRegSt(GAIN_REG_st *st);

该函数可以使用 -> 运算符访问结构体字段:

st->data_u8 = 1;

用法:

G_u g;
...
populateGainRegSt( &(g.GAIN_st));

Prototype:

int populateGainRegSt(GAIN_REG_st *st);

The function may access the structure fields using -> operator:

st->data_u8 = 1;

Usage:

G_u g;
...
populateGainRegSt( &(g.GAIN_st));
停滞 2024-11-08 17:58:03
#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;
}
#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;
}
迟到的我 2024-11-08 17:58:03

C89 没有真正规定直接初始化和传递联合作为参数。在 C89 中,联合只能使用变量或变量引用来声明,然后必须使用变量进行初始化。但是,您可以按值传递和返回这些变量,因此无需使用指针。

返回的结构和联合不需要像普通返回参数一样适合寄存器。在这种情况下,编译器会为您做所有事情(在堆栈上),如果它是深度优化和内联的,这通常不会涉及太多开销(阅读:仔细手工优化的 C 代码可能会更快,但是优化器通常会做相当多的事情)好工作)。

下面是示例代码。

使用实用函数 create_GAIN_REG_stGAIN_REG_st_to_G_u,您可以在调用函数的参数列表上动态创建结构体/联合,该函数接受这些作为参数)。

请注意,这种方式仅适用于非指针类型,因为指针必须指向某个地方。如果使用指针,则需要malloc/free。但是,通过返回整个数据类型,您就不需要它了。一件重要的事情是,您可以获得指向动态创建的数据的指针,但数据仅在调用期间存在,就像堆栈上的变量一样 - 这可能很快导致“释放后使用”或别名为重新的指针- 使用的堆栈区域。 (因此,始终避免指向作为参数传递的结构/联合的指针,这些指针会被返回或临时变量。)

#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;
}

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;
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文