Question.5
A developer casts a received UART byte buffer to a struct pointer:
typedef struct {
uint8_t start;
uint32_t data;
uint8_t crc;
} Packet;
uint8_t rx_buf[6] = {0xA5, 0x01, 0x34, 0x12, 0x77, 0x5A};
Packet *pkt = (Packet *)rx_buf;
printf("%u", pkt->data);The developer expects data to be 0x1234 (bytes 0x34 and 0x12 at indices 2 through 3).
Which of the following statements are correct regarding this implementation?
I. The output will not match due to compiler padding.
II. The struct maps perfectly to the buffer layout.
III. The cast would be safe if the struct were explicitly packed.A struct groups different types of related data into one unit.
typedef struct {
uint8_t id;
float temperature;
uint16_t status;
} Sensor;This creates a custom type Sensor which holds:
You can then declare and use:
Sensor s1 = {1, 36.5, 0x0001};
printf("ID: %d, Temp: %.1f, Status: %04X\n", s1.id, s1.temperature, s1.status);Via variable:
Sensor s;
s.id = 2;
Via pointer:
Sensor *ptr = &s;
ptr->temperature = 25.3;This is crucial in firmware, where structs often represent memory-mapped registers.
Used to simulate bit-level control like hardware registers:
typedef struct {
uint8_t RX_Ready : 1;
uint8_t TX_Ready : 1;
uint8_t Error : 1;
uint8_t Reserved : 5;
} UART_Status;
UART_Status status;
status.RX_Ready = 1;
A union lets you access the same memory in multiple ways.
typedef union {
struct {
uint8_t EN : 1;
uint8_t MODE : 2;
uint8_t INT : 1;
uint8_t : 4; // reserved
} bits;
uint8_t value;
} ControlRegister;
ControlRegister reg;
reg.value = 0x00;
reg.bits.EN = 1;
reg.bits.MODE = 3; // sets 2 bits
printf("CTRL: %02X\n", reg.value); // Outputs: CTRL: 0DHelps build control registers for GPIO/UART/ADC.
Modern processors access memory faster when variables are aligned to their natural size boundaries (e.g., 4-byte variables aligned to 4-byte addresses).
For example:
typedef struct {
char a; // 1 byte
int b; // 4 bytes (aligned)
} MyStruct;
Even though a is 1 byte, the total size may be 8 bytes:
Why padding(3 bytes) is added
Check:
printf("Size = %lu\n", sizeof(MyStruct)); // Likely 8In firmware, padding matters when:
To avoid padding:
typedef struct __attribute__((packed)) {
char a;
int b;
} PackedStruct;Use with caution:
You can define a struct to match hardware layout:
typedef struct {
uint32_t CTRL;
uint32_t STATUS;
uint32_t DATA;
} Peripheral;
#define PERIPH_BASE 0x40010000
#define PERIPH ((volatile Peripheral *) PERIPH_BASE)
PERIPH->CTRL = 0x01;You now access registers using PERIPH->STATUS, etc.
typedef struct {
uint32_t BAUD;
uint8_t PARITY;
uint8_t STOP_BITS;
} UART_Config;
UART_Config uart = {9600, 0, 1};
UART_Config *p = &uart;
printf("Baud: %d", p->BAUD);Used in drivers, initializations, and configs.
| Feature | Firmware Use Case |
|---|---|
| struct | Group related config/data (e.g., sensor, GPIO) |
| Bitfield | Control or status registers |
| Union+Bitfield | Register + flag overlay |
| Packed Struct | Communication packet formatting |
| Struct Pointer | API for device driver interface |
| Mistake / Tip | Details |
|---|---|
| ❌ Using . instead of -> | Use . for variable, -> for pointer |
| ❌ Assuming layout across platforms | Bitfield order is compiler-specific |
| ❌ Misaligned struct on hardware | Leads to bus fault on some MCUs |
| ✅ Always use stdint.h types | uint8_t, uint16_t ensures exact sizes |
| ✅ Check sizeof() | Helps verify memory layout |
| ✅ Avoid float inside hardware registers | Use only integers for mapped structs |