?
Solved

Memory Alignment

Posted on 2006-05-10
2
Medium Priority
?
975 Views
Last Modified: 2012-06-27
Please can someone explain the memory alignment for advancing an short array pointer cast to a void*.
Thanks!
0
Comment
Question by:luoys
2 Comments
 
LVL 32

Expert Comment

by:jhance
ID: 16652678
Memory alignment, in the x86 world at least, has to do with performance rather than operability.  That means that the x86 family CPUs can access a byte of data regardless of how it's aligned in memory but that doing so might be much slower than if the data were aligned on a 32-bit or with newer CPUs, 64-bit boundary.  Some CPUs, most notably the HP PA RISC, PowerPC, and Sun SPARC chips cannot access data on anything but a 32-bit boundary and attempts to do an unaligned access will cause a fault.

So what is alignment?  We often think of byte in programming and bytes are 8-bit pieces of data.  On an 8-bit CPU (like an 8080, Z80, 6800, 6502, etc.) alignment is not an issue since each memory address represents one and only one byte.

On a 16-bit CPU (8086, 68000, etc.) it's more complicated.  Each memory address now represents 16-bits or TWO bytes.  So when you access a memory element you may be interested in the full 16-bit value or you may be interested in either the upper or lower 8-bits of the 16-bit value.  Here's where it gets tricky.  Normally you'd store that 16-bit value at an EVEN address like 0, 2, 4, 6, ... since the ODD addresses, 1, 3, 5, 7, ... represent the UPPER 8-bits of the 16-bit value, at least on an x86 CPU.  That's OK and you can read BYTES at any address.  But what do you get if you try to READ a 16-bit WORD at address 1?  This is alignment at work.  In the x86 CPU, this causes TWO read cycles, one to get the upper byte of address 0 and another to get the lower byte of address 2 so that when they are assembled you can have the 16-bit value at address 1.  So while this is possible, on the x86 CPU at least, it's not desirable for the most part because it takes 2X as long to read.  

On a 32-bit CPU (80386 and beyond) you have even more possibilities since any address has possibly 4 8-bit values, two 16-bit values, or one 32-bit values.  And even more alignment confusion is possible.

In general, when programming, it's best to let the compiler adjust the alignment automatically for best performance on your target CPU.  It will often add padding bytes when needed so that it keeps data aligned on a 32-bit boundary.

Why would you NOT want this to happen?  There are some specific reasons.  The most common is when you have an existing data structure (perhaps from a database a network socket or something else you have to live with and can't change) and you must either read or write to that structure in a compatible way.  While there are other ways to do this that don't involve non-aligned access, you MAY want to use this option to make your job simpler.
0
 
LVL 3

Accepted Solution

by:
steveiam earned 2000 total points
ID: 16654630
Adding to what jhance said, I think good alignment also comes into play when optimising code, and use of the processor's onchip L1 and L2 caches, for similar reasons.  Also, some processors are actually unable to do non-aligned reads.  If you try to do one, the processor will fault, stop running your program, and jump to an error routine.  

Because byte alignment is something very specific to processor type, its something you shouldn't worry about while programming, unless you really _really_ have to.  In addition to that, different compilers and architectures have different sizes for things like "short" "int", and pointers, making it harder to write cross-platform compatible code.  void* pointers should be avoided if possible, as they throw away valuable information on the type/size of the data its pointing at or representing.

Back to your question: once a pointer is cast to "void *", there is no way of knowing what size datatype it was pointing to in the first place, so it can't move appropriately.  My compiler (gcc on FreeBSD on an Intel celeron) generates increments of 1 to a void* pointer, even if it was cast from a 4-byte type:

  int t[2]; // an array of integers
  int *t2 = t; // an integer pointer
  void *t3 = (void *)t; // an integer pointer cast to a void*

  printf("%x %x %x\n",t,t2,t3); // print out the address that the pointer points to
  printf("%x %x %x\n",t+1,t2+1,t3+1); // print out the address "plus one"

gives:

  bfbfe830 bfbfe830 bfbfe830
  bfbfe834 bfbfe834 bfbfe831

You can see that the two integer pointers incremented by 4 (which is sizeof(int)), while the void* pointer has only incremented by one.
0

Featured Post

Concerto's Cloud Advisory Services

Want to avoid the missteps to gaining all the benefits of the cloud? Learn more about the different assessment options from our Cloud Advisory team.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Whether you’re a college noob or a soon-to-be pro, these tips are sure to help you in your journey to becoming a programming ninja and stand out from the crowd.
Computer science students often experience many of the same frustrations when going through their engineering courses. This article presents seven tips I found useful when completing a bachelors and masters degree in computing which I believe may he…
Six Sigma Control Plans
Progress

850 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question