Advertisement

MS C++ annoying data alignment.

Started by August 01, 2018 08:19 PM
13 comments, last by Gnollrunner 6 years, 1 month ago

8 byte alignment is what you're going to want for most cases on x64.
You can get a B without an A just by casting it and you don't want all of your B pointers misaligned.


The standard is mute on this subject as it is implementation defined behavior.
vtables are not mandated, a given implementation could do something different.

- The trade-off between price and quality does not exist in Japan. Rather, the idea that high quality brings on cost reduction is widely accepted.-- Tajima & Matsubara
22 minutes ago, Shannon Barber said:

8 byte alignment is what you're going to want for most cases on x64.
You can get a B without an A just by casting it and you don't want all of your B pointers misaligned.


The standard is mute on this subject as it is implementation defined behavior.
vtables are not mandated, a given implementation could do something different.

Actually you can't get B without A, only A without B, and with no multiple inheritance, casting either way will not move pointers.

Advertisement
4 minutes ago, Gnollrunner said:

Actually you can't get B without A, only A without B, and with no multiple inheritance, casting either way will not move pointers.

I suppose I did get it backwards - if you have base-class pointers, A's then, you'll want those pointers aligned.
When you vector to B virtual functions you will want that look-up aligned.

If you follow the POD rules (plain ol' data-type) you should see it compact.

- The trade-off between price and quality does not exist in Japan. Rather, the idea that high quality brings on cost reduction is widely accepted.-- Tajima & Matsubara

I'm surprised by the g++ behavior for B. This means that if you static_cast<B*> your struct, you will get a pointer that is not 8-byte aligned. While this is legal (things smaller than the word size only need to be aligned to their natural alignment) I'd expect the beginning of every allocation to be 8-byte aligned or better, and the beginning of each compound object to be similarly aligned. MSVC apparently agrees with me, and g++ doesn't.

Separately, g++ would then also be expected to return a 4-byte aligned pointer when calling "new B[1]" -- I wonder if it ever does that? I would expect not.

Drawing this into the extreme, I'd expect g++ to return a one-byte-aligned pointer when calling "new char[1]" but I'm pretty sure it won't :-)

enum Bool { True, False, FileNotFound };
1 hour ago, hplus0603 said:

 

Separately, g++ would then also be expected to return a 4-byte aligned pointer when calling "new B[1]" -- I wonder if it ever does that? I would expect not.

Drawing this into the extreme, I'd expect g++ to return a one-byte-aligned pointer when calling "new char[1]" but I'm pretty sure it won't ?

I think perhaps you are misunderstanding a couple things.  First B always includes A. In memory the layout will be A followed by B tacked on the bottom so even in g++ B is in fact 8 byte aligned. The only thing that isn't 8 byte aligned is the member of B (i.e. b) because it doesn't have to be. Had it been a double the compiler would have 8 byte aligned it. I'm not sure why MS C++ does it otherwise. It seems like a waste of memory.  This will be especially true of there are a lot of levels of inheritance. I'm wondering if there is a compiler switch somewhere.

As for new char[1], that's a different issue. It is legal for the "new" to align it by one if it wants, but I believe new has to be a single function because you can overload it and therefore it has to align to the most conservative alignment. On the other hand, it gets passed the size so it could make some decision if that size is less than the most conservative alignment for a specific architecture. In any case you can write your own new and even write it on a per class basis so there are a lot of things you can do if you want to.

The other thing is new and delete has to know the size of objects and in the case of arrays this has to be explicitly stored somewhere. This is generally done before the object in memory and that number itself has to be aligned which can result in alignment of the memory that follows..... whew!......  a lot of variables

All this being said, in my experience system allocated memory is always aligned conservatively just to keep things simple, but again that is not really related to the internal memory layout of a given class.

This topic is closed to new replies.

Advertisement