Как передать объединение в качестве параметра функции - PullRequest
8 голосов
/ 18 апреля 2011

Этот код предназначен для драйвера для ЦАП микросхемы.

У меня есть битовое поле ниже, которое представляет 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 в функцию, когда она находится внутри объединения?(Можете ли вы показать прототип функции и вызов)?

Как функция получает доступ к членам битового поля?(это будет похоже на G_u.GAIN_st.rdwr_u8 = 1?)

Ответы [ 5 ]

7 голосов
/ 18 апреля 2011
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;
}

Вы имеете в виду это?это союз, так зачем сдавать внутреннего члена?это не будет иметь никакого значения.Все они начинаются с одинакового смещения памяти.

4 голосов
/ 18 апреля 2011

Заголовок о прохождении объединения, но возникает вопрос о прохождении структуры. Вы можете сделать либо, вы просто объявляете аргумент функции соответствующим образом и передаете либо член, либо весь союз.

Все текущие ответы демонстрируют передачу по ссылке, но в этом нет необходимости, вы можете передать копию, что для структуры или объединения, которое в конечном итоге является 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 );
}

Почти наверняка не будет разницы в накладных расходах между передачей структуры или объединения. Это просто вопрос того, где вы решите раскрыть знания о внутреннем представлении.

1 голос
/ 18 апреля 2011

Прототип:

int populateGainRegSt(GAIN_REG_st *st);

Функция может получить доступ к полям структуры, используя оператор ->:

st->data_u8 = 1;

Использование:

G_u g;
...
populateGainRegSt( &(g.GAIN_st));
0 голосов
/ 06 декабря 2015

C89 не имеет реального условия для инициализации и передачи союзов в качестве аргументов напрямую. В C89 союзы могут быть объявлены только с использованием переменных или ссылок на переменные, а затем должны быть инициализированы с использованием переменной. Однако затем вы можете передавать и возвращать эти переменные по значению, поэтому без использования указателей.

Возвращаемые структуры и объединения не должны вписываться в регистры, как обычные возвращаемые параметры. В этом случае компилятор делает все за вас (в стеке), и если он глубоко оптимизирован и встроен, это обычно не требует больших накладных расходов (читай: осторожно оптимизированный вручную код C может быть быстрее, однако часто оптимизатор делает довольно хорошая работа).

Ниже приведен пример кода.

С помощью служебных функций create_GAIN_REG_st и GAIN_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;
}
0 голосов
/ 18 апреля 2011
#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;
}
...