energetic
energetic

Reputation: 897

ARM GCC Address of packed struct warning

In my code, I have something like this:

#include <stdint.h>

typedef struct __attribute__((packed)) {
    uint8_t test1;
    uint16_t test2;
} test_struct_t;
test_struct_t test_struct;

int main(void)
{
    uint32_t *ptr = (uint32_t*) &test_struct;
    return 0;
}

When I compile this using arm-none-eabi-gcc, I get the warning

.\test.c:11:2: warning: converting a packed 'test_struct_t' pointer (alignment 1) to a 'uint32_t' {aka 'long unsigned int'} pointer (alignment 4) may result in an unaligned pointer value [-Waddress-of-packed-member]

Can anyone tell me why this is happening? Taking the address of a packed struct member is of course dangerous. But the whole struct itself should always be aligned, shouldn't it?

Upvotes: 3

Views: 3622

Answers (3)

David
David

Reputation: 162

In my experience, "packed" structs are almost always a bad idea. They don't always do what people think they do, and they might do other things as well. Depending on compilers, target processors, options, etc., you might find the compiler generating code that uses multiple byte accesses to things that you expect to be 16-bit or 32-bit accesses.

Hardware registers are always going to be properly aligned on a microcontroller. (Bitfields may be a different matter, but you are not using bitfields here.) But there might be gaps or padding.

And the whole idea of trying to access this using a pointer to a uint32_t is wrong. Don't access data via pointer casts like this - in fact, if you see a pointer cast at all, be highly suspicious.

So how do you get a structure that matches a hardware structure exactly? You write it out explicitly, and you use compile-time checks to be sure:

#pragma GCC diagnostic error "-Wpadded"

struct TestStruct {
    uint8_t test1;
    uint8_t padding;
    uint16_t test2;
};

_Static_assert(sizeof(struct TestStruct) == 4, "Size check");

The padding is explicit. Any mistakes will be caught by the compiler.

What if you really, really want an unaligned 16-bit field in the middle here, and you haven't made a mistake in reading the datasheets? Use bitfields:

#pragma GCC diagnostic error "-Wpadded"

struct TestStruct2 {
    uint32_t test1 : 8;
    uint32_t test2 : 16;
    uint32_t padding : 8;
};

_Static_assert(sizeof(struct TestStruct2) == 4, "Size check");

Put the padding in explicitly. Tell the compiler to complain about missing padding, and also check the size. The compiler doesn't charge for the extra microsecond of work.

And what if you really, really, really need to access this as a uint32_t ? You use a union for type-punning (though not with C++) :

union TestUnion {
    uint32_t raw;
    struct TestStruct2 s;
};

Upvotes: 2

SergeyA
SergeyA

Reputation: 62553

There is an answer in the comments, but since it's author didn't post it, I take the liberty to post it myself. All the credit is due to @Clifford.

By default, when the struct is packed, compilers also change alignment of the struct to 1 byte. However, for your case you need the struct to be both packed and aligned as 32-bit unsigned integer. This can be done by changing the packing attribute as following:

#include <stdint.h>

struct __attribute__((packed, aligned(sizeof(uint32_t)))) TestStruct {
    uint8_t test1;
    uint16_t test2;
};

struct TestStruct test_struct;

int32_t* p = (int32_t*)(&test_struct);

This compiles for ARM platform without any warnings.

Upvotes: 4

Adrian Mole
Adrian Mole

Reputation: 51815

Your packed structure has a size of 3 bytes, and there can be no padding in it. Thus, if we were to create an array of such structures, with the first element having a 4-byte aligned address then, by the definition of arrays (contiguous memory), the second element would be three bytes (sizeof(struct test_struct_t)) from that. Thus, the second element would have only single byte alignment – so, the alignment requirement of your structure is, by deduction, one byte.

On your ARM platform, a unit32_t requires 4 byte alignment, hence the warning.

Upvotes: 0

Related Questions