In the comments to your post you have the explanation of the why it warns and why it can be a bad idea to take a pointer of a non-aligned member. The issue is not so much about assigning an unaligned value to a pointer (which seems to be permitted by bullet 5 of 6.3.2.3 here, but only about dereferencing it. Dereferencing it seems to be even explicitly permitted on some architectures, albeit with a performance penalty (e.g.: on x86 when not using SSE load/store), but it may cause severe issues depending on type and generated assembly on other architectures, typically a BUS ERROR if you are in user space or a fault if you are in kernel space.
For bad that it may be to do something like that, there is code around that takes pointers of packed struct's elements
and even dereferences them without shame:
https://github.com/abperiasamy/rtl8812AU_8821AU_linux/blob/4d1726146fd96552c9fa5af05c75187027d6885b/core/rtw_cmd.c#L1481
https://github.com/abperiasamy/rtl8812AU_8821AU_linux/blob/4d1726146fd96552c9fa5af05c75187027d6885b/core/rtw_mlme.c#L3689
I can imagine that someone may be in a situation where they are stuck with someone else's code with a packed struct (note that it would be bad to have a packed struct in a library's header file, as packing is a non-standard extension to the language and its results are compiler dependent). Or maybe they have a function that is guaranteed to deal properly with an unaligned pointer; as the C standard provides no way to communicate that in the code, one would have to rely on the function's documentation (and/or implementation) to figure that.
Now that you understand what's wrong with it but also that it can sometimes be useful to suppress that warning locally without setting a global compiler option; here's an answer to:
How to get rid of this warning without using [-Wno-address-of-packed-member]
You can use the base address to the struct and add to it the relevant offset, obtained via offsetof()
. This requires some casting and, even turned into a macro, it is not particularly clean as it requires several arguments:
#define member_nowarn(structType, elementType, structPtr, memberName) \
((elementType*)(((char*)(structPtr)) + offsetof(structType, memberName)))
This can be simplified so you don't have to pass the elementType
, but then the return value of the macro will be a void*
which means compiler warnings may get suppressed when you mistakenly pass it to a function that expects a pointer to something else than the type of the memberName
element, so I wouldn't recommend this:
#define member_nowarn_unsafe(structType, structPtr, memberName) \
((void*)((((char*)(structPtr)) + offsetof(structType, memberName))))
If your compiler supports the non-standard typeof()
(e.g.: this is provided by stddef.h
in gcc
), you can simplify the macro so that no type has to be passed, the returning pointer's type is still correct and the code using it becomes simpler and less error-prone:
#define member_nowarn_nostd(structPtr, memberName) \
((typeof((structPtr)->memberName)*)(((char*)(structPtr)) + offsetof(typeof(*(structPtr)), memberName)))
Example code:
#include <stdio.h>
#include <stddef.h>
#include <string.h>
typedef float MYTYPE;
struct details {
char mychar;
MYTYPE mymember;
} __attribute__((packed));
struct details d;
void myfunc(MYTYPE*);
#define member_nowarn(structType, elementType, structPtr, memberName) \
((elementType*)(((char*)(structPtr)) + offsetof(structType, memberName)))
#define member_nowarn_unsafe(structType, structPtr, memberName) \
((void*)((((char*)(structPtr)) + offsetof(structType, memberName))))
#define member_nowarn_nostd(structPtr, memberName) \
((typeof((structPtr)->memberName)*)(((char*)(structPtr)) + offsetof(typeof(*(structPtr)), memberName)))
int main()
{
d.mymember = 123;
// warns
myfunc(&d.mymember);
//warns
myfunc((MYTYPE*)&d.mymember);
// ugly, but it does't warn
myfunc(((MYTYPE*)((char*)(&d) + offsetof(struct details, mymember))));
// same, turned into a macro
myfunc(member_nowarn(struct details, MYTYPE, &d, mymember));
// simpler, but the return value of the macro is void* so you won't get a
// warning when passing to a function that requires a different type of pointer
myfunc(member_nowarn_unsafe(struct details, &d, mymember));
// simpler macro, but uses non-standard typeof()
myfunc(member_nowarn_nostd(&d, mymember));
return 0;
}
void myfunc(MYTYPE* arg)
{
MYTYPE val;
// do not dereference the pointer: it may crash
// depending on MYTYPE, architecture and the generated
// assembly.
// val = *arg; // don't do this
// instead use memcpy to get the data it points to
memcpy(&val, arg, sizeof(val));
printf("%p %f\n", arg, (double)val);
}
struct details_state
needs to be beforestruct details
. – Celeski__attribute__((packed))
. – Monoclinousstruct details_status
is missing): aligned addresses and a packed structure. You need to choose one of them. – Brottmanmemcpy
and pass the address of the copy. – Irreformablememcpy
will work without any alignment requirement. Therefore you can copy the mis-aligned memory area into well-alignemd memory area and then take the address for calling your function. – Irreformable