Reputation: 1998
i want to test if it is OK to access a mis-aligned member of a structure in C, please see the code
#include <stdio.h>
#pragma pack(1) /* force 1 byte alignment */
/* either member b or member d is mis-aligned */
typedef struct
{
int b;
unsigned char c;
unsigned int d;
}A ;
int main(int argc, char *argv[])
{
A _a = {0};
unsigned int *p = NULL;
unsigned int *q = NULL;
printf("addr of _a : 0x%08x, size of _a : %u\n", &_a, sizeof(_a));
p = (unsigned int*)(&_a.b);
q = (unsigned int*)(&_a.d);
/* should this fail ? */
(*p)++ , (*q)++;
return 0;
}
assume the program will crash due to an exception caused by the mis-aligned memory access, but it turns out that it works quite well, have tested in Linux 3.6.11(GCC 4.7.2) , WinXP(MingW), codepad online compiler(http://codepad.org/yOoc8ACG)
please explain the result, i guess the OS have done something to save the program, still doubt if it works in VxWorks or some other operating systems
note: the code runs on an Intel-based machine!
thanks in advance !
Upvotes: 3
Views: 1929
Reputation: 129504
Some of the answers above say that "since it's x86, it won't fail", which isn't entirely correct. Whilst I know of no OS that does that, it's possible to configure the x86 processors to fault on unaligned access in user-mode [not in kernel mode, but the code posted looks like user-mode code to me]. But like I said, I know of not a single OS that actually configures this bit, and it would quite possibly break some code that isn't expecting the processor to fault for unaligned memory access.
The behaviour of unaligned access, no matter how you view it, is undefined or at best implementation defined. This means that the result from such an operation ranges from "it works just like you expect it to" at one end of the spectrum to "the program crashes". In the middle of that range are perhaps the worse options of "it doesn't crash, but it also doesn't quite behave as you expect" - for example, you may find that you get the value corresponding to the aligned address just before [lower memory address] the data you expected to fetch, or the fetch is indeed performed correctly, but it takes 10 or 100 times longer than the aligned variant, due to the processor trapping and performing the operation in several steps, then returning from the trap. If you are also running multiple threads, you may also find that updates to the variable isn't done in an atomic way, so you get values that are "half of one, half of another", which can clearly lead to very strange effects. This is NOT a conclusive list of the potential scenarios of "things going a bit wrong, but not in an immediately obvious way".
My advice is: Don't mess with alignment, and make your absolute best effort to never write code that accesses elements that aren't aligned. It will probably come back and bite you sooner or later...
Upvotes: 2
Reputation: 5163
The result depends on architecture and kernel configuration. Usually on x86 you can access misaligned data with some performance penalty. This is mainly due to compatibility to older family of CPUs.
On ARM and SPARC the behavior depends on kernel configuration. This misaligned data access can be prohibited, allowed, or even emulated by OS. In the latter case a hardware exception is intercepted by kernel and emulated with some OS' peace of code.
This becomes more difficult with compiler version coming into place. Modern GCC, for example, generates a special code that can access misaligned data in non-atomic way (i.e. with several instructions), if it sees that the data is not aligned.
Upvotes: 0
Reputation: 279375
x86-based architectures are unusual, in that their word-access instructions can be used on mis-aligned addresses. The resulting operation is slower and non-atomic, but it works.
As soon as your program contains a #pragma
its meaning is (at best) implementation-defined. Generally speaking, assigning the address of the data member to an unsigned int*
variable will make the implementation "forget" that it might be mis-aligned, so it won't emit code for an unaligned load. Hence on architectures where it matters, either *p
or *q
(or both) won't work.
Upvotes: 0
Reputation: 225122
Presumably you're running on an Intel machine. The x86 architecture can handle misaligned accesses without any problems. You might have problems on other architectures, though. Even if an architecture happens to not support misaligned accesses, you're right that sometimes the operating system can work around it for you by emulating the misaligned access with single-byte accesses in some kind of CPU exception handler.
I think you want (*p)++
and (*q)++
in your test program, too.
Upvotes: 2