Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there any guarantee of alignment of address return by C++'s new operation?

Most of experienced programmer knows data alignment is important for program's performance. I have seen some programmer wrote program that allocate bigger size of buffer than they need, and use the aligned pointer as begin. I am wondering should I do that in my program, I have no idea is there any guarantee of alignment of address returned by C++'s new operation. So I wrote a little program to test

for(size_t i = 0; i < 100; ++i) {     char *p = new char[123];     if(reinterpret_cast<size_t>(p) % 4) {         cout << "*";         system("pause");     }     cout << reinterpret_cast<void *>(p) << endl; } for(size_t i = 0; i < 100; ++i) {     short *p = new short[123];     if(reinterpret_cast<size_t>(p) % 4) {         cout << "*";         system("pause");     }     cout << reinterpret_cast<void *>(p) << endl; } for(size_t i = 0; i < 100; ++i) {     float *p = new float[123];     if(reinterpret_cast<size_t>(p) % 4) {         cout << "*";         system("pause");     }     cout << reinterpret_cast<void *>(p) << endl; } system("pause"); 

The compiler I am using is Visual C++ Express 2008. It seems that all addresses the new operation returned are aligned. But I am not sure. So my question is: are there any guarantee? If they do have guarantee, I don't have to align myself, if not, I have to.

like image 768
Fang-Pen Lin Avatar asked Feb 03 '09 09:02

Fang-Pen Lin


People also ask

How do I know if my address is aligned?

In any case, you simply mentally calculate addr%word_size or addr&(word_size - 1) , and see if it is zero. When the address is hexadecimal, it is trivial: just look at the rightmost digit, and see if it is divisible by word size. For a word size of 4 bytes, second and third addresses of your examples are unaligned.

Does malloc guarantee alignment?

The only standard rule is that the address returned by malloc will be suitably aligned to store any kind of variable. What exactly that means is platform-specific (since alignment requirements vary from platform to platform).

What is an aligned address?

The alignment of the access refers to the address being a multiple of the transfer size. For example, an aligned 32 bit access will have the bottom 4 bits of the address as 0x0, 0x4, 0x8 and 0xC assuming the memory is byte addressed. An unaligned address is then an address that isn't a multiple of the transfer size.

Why is memory alignment required?

The CPU can operate on an aligned word of memory atomically, meaning that no other instruction can interrupt that operation. This is critical to the correct operation of many lock-free data structures and other concurrency paradigms.


2 Answers

The alignment has the following guarantee from the standard (3.7.3.1/2):

The pointer returned shall be suitably aligned so that it can be converted to a pointer of any complete object type and then used to access the object or array in the storage allocated (until the storage is explicitly deallocated by a call to a corresponding deallocation function).

EDIT: Thanks to timday for highlighting a bug in gcc/glibc where the guarantee does not hold.

EDIT 2: Ben's comment highlights an intersting edge case. The requirements on the allocation routines are for those provided by the standard only. If the application has it's own version, then there's no such guarantee on the result.

like image 128
Richard Corden Avatar answered Sep 27 '22 17:09

Richard Corden


This is a late answer but just to clarify the situation on Linux - on 64-bit systems memory is always 16-byte aligned:

http://www.gnu.org/software/libc/manual/html_node/Aligned-Memory-Blocks.html

The address of a block returned by malloc or realloc in the GNU system is always a multiple of eight (or sixteen on 64-bit systems).

The new operator calls malloc internally (see ./gcc/libstdc++-v3/libsupc++/new_op.cc) so this applies to new as well.

The implementation of malloc which is part of the glibc basically defines MALLOC_ALIGNMENT to be 2*sizeof(size_t) and size_t is 32bit=4byte and 64bit=8byte on a x86-32 and x86-64 system, respectively.

$ cat ./glibc-2.14/malloc/malloc.c: ... #ifndef INTERNAL_SIZE_T #define INTERNAL_SIZE_T size_t #endif ... #define SIZE_SZ                (sizeof(INTERNAL_SIZE_T)) ... #ifndef MALLOC_ALIGNMENT #define MALLOC_ALIGNMENT       (2 * SIZE_SZ) #endif 
like image 44
user1059432 Avatar answered Sep 27 '22 17:09

user1059432