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