[C++] Alignment and arrays
So you honestly believe that reading the second character in an array of chars on architectures that have memory alignment exceptions will cause the program to crash? You don't think the small fact that any software at all runs on these platforms is a counter example?
Quote:Original post by thatguyfromthething
Then you continue to stir things up even though I ignored your last post. This is a subject you don't know as much about as I do and coming out and saying 'you are guilty of...blah blah blah' when you ought to be humbly apologizing is not a great way to carry yourself.
Sorry, I think you are the one that doesn't know what he is talking about. The fact that a particular allocator prepends the block size just before the pointer it returns doesn't mean anything about the alignment of such pointer. How about you run some simple test and show us that indeed you get 4+something_round? I believe you'll find out that you were wrong.
I don't know of any architecture where you cannot access individual bytes anywhere. Almost by definition, a byte is the smallest size you can get a pointer to; at least that's the way I think about them, and I still haven't found a situation where this rule doesn't work. There are machines where 4-byte types have to be aligned to 4-byte boundaries and 8-byte types have to be aligned to 8-byte boundaries (e.g., Sparc), but I don't think there are any where you can't read whatever byte you want.
You are spreading a lot of misinformation and should be more careful about your statements. The issue at hand is confusing enough without your help.
Quote:Original post by thatguyfromthething
Then you continue to stir things up even though I ignored your last post. This is a subject you don't know as much about as I do and coming out and saying 'you are guilty of...blah blah blah' when you ought to be humbly apologizing is not a great way to carry yourself.
Considering that one of your statements re:memory alignment has been proven wrong above I think you have that backwards.
While I know that a mod has contacted you about your conduct in this thread I am also going to say here and now that any further posting in this thread on the subject without demonstrable proof (be it in code form or a 3rd party link to back up your claims) is going to lead to your posts being deleted and a 2 day suspension carried out.
Quote:Original post by thatguyfromthething
Yes, I saw it. I ignored it because it's meaningless. Of course an aligned struct is going to line up, the compiler specifically aligns it. Which does not go anything against what I said.
Does the following go against what you said? Or is this an error in my understanding of what you said?
Quote:Original post by thatguyfromthething
malloc (for vc++ 2008 anyway, and most others) always returns an aligned to 16 (or is it 8?) value. It has allocation size prepended but that is invisible to you even if you overload operator new[].
operator new[] is on top of malloc.
So, after prepending (you cant avoid this), the return value is always whatever malloc returned offset by sizeof(int).
That means you are never starting on 16 byte aligned boundary for array.
struct sixteen_bytes { float a; float b; float c; float d; };int main(int argc, char** argv){ sixteen_bytes* array = new sixteen_bytes[100]; std::cout << "Size: " << sizeof(sixteen_bytes) << "\n" << "Addr: 0x" << std::hex << array << "\n" << "Mod 16: " << std::dec << ((int)array % 16) << std::endl;}
Size: 16
Addr: 0x00624E10
Mod 16: 0
VC++ 2008
Quote:Original post by thatguyfromthething
Just make a couple array with items sized 16 bytes, then use simd instruction. It crashes every time unless you use a compiler directive to align them properly.
This is exactly what I did above. I can augment my code to use SIMD instructions if you like, but I think it should be sufficient to demonstrate that the pointer is aligned on a 16-byte boundary. Did I misread your requirements somehow? I'm being serious. You said that nothing went against what you said, so I feel like maybe I just didn't understand what you said. It really looks to me like you said in VC++ allocating an array of values whose size are 16-bytes, the returned pointer will never be 16 byte-aligned. Please elaborate on how my example above does not conflict with this.
[Edited by - cache_hit on March 2, 2010 8:40:37 PM]
struct sixteen_bytes { float a; float b; float c; float d; };int main(int argc, char** argv){ for (int i = 0; i < 1000; i++) { sixteen_bytes* array = new sixteen_bytes[rand() % 4096 + 1]; int m = (int)array % 16; if (m) { std::cout << "Size: " << sizeof(sixteen_bytes) << "\n" << "Addr: 0x" << std::hex << array << "\n" << "Mod 16: " << std::dec << m << std::endl; return 0; } }}
Fails for 32-bit build.
Quote:i: 1
Size: 16
Addr: 0x00571068
Mod 16: 8
It doesn't fail for 64-bit.
Although it's hard to determine who is right, since details of how an array is allocated are undefined and implementation specific, and which alignment one should expect is also a matter of debate depending on whether SIMD is used or not.
From observations above it would appear that in 32 bit test application all allocations were on 8-byte boundary, while in 64-bit application they were 16-byte aligned (or 32, I didn't test).
Edit: Oh joy.
Quote:malloc is required to return memory on a 16-byte boundary.
Now either 32-bit version is broken, or documentation is incorrect, or malloc isn't used by new, or arrays are allocated differently, ....
It's even better :)
Size: 16
Zeros: 497
Eights: 503
Wtfs: 0
That's a 32-bit build.
On a 64-bit build I get the following:
Size: 16
Zeros: 1000
Eights: 0
Wtfs: 0
Either way, the claim that array new can never return addresses aligned on a 16-byte boundary is ALWAYS wrong, since it clearly can.
#include "stdafx.h"#include <math.h>#include <iostream>struct sixteen_bytes { float a; float b; float c; float d; };int main(int argc, char** argv){ int zeros=0; int eights=0; int wtfs=0; for (int i = 0; i < 1000; i++) { sixteen_bytes* array = new sixteen_bytes[rand() % 4096 + 1]; int m = (int)array % 16; if (m==0) ++zeros; else if (m==8) ++eights; else ++wtfs; } std::cout << "Size: " << sizeof(sixteen_bytes) << "\n" << "Zeros: " << zeros << "\n" << "Eights: " << eights << "\n" << "Wtfs: " << wtfs << "\n"; return 0;}
Size: 16
Zeros: 497
Eights: 503
Wtfs: 0
That's a 32-bit build.
On a 64-bit build I get the following:
Size: 16
Zeros: 1000
Eights: 0
Wtfs: 0
Either way, the claim that array new can never return addresses aligned on a 16-byte boundary is ALWAYS wrong, since it clearly can.
Also, the CRT source code ships with Visual Studio. You can just look at it.
operator new[] directly calls operator new. operator new directly calls _heap_alloc. _heap_alloc is #define'd to _heap_alloc_base in debug, and in release it directly calls HeapAlloc.
This refutes the poster's other claim, in particular that operator new[] sits on top of malloc. So it turns out that basically everything about the post was wrong. Or at least that's what I'm seeing, unless I just misread it.
There is another version of operator new that does use malloc, but it depends on certain #define. I think it's probably the case most of the time that it uses malloc due to the #define's default behavior, but obviously "operator new[] sits on top of malloc" does not appear to be a universally true statement, even with MSVC.
operator new[] directly calls operator new. operator new directly calls _heap_alloc. _heap_alloc is #define'd to _heap_alloc_base in debug, and in release it directly calls HeapAlloc.
This refutes the poster's other claim, in particular that operator new[] sits on top of malloc. So it turns out that basically everything about the post was wrong. Or at least that's what I'm seeing, unless I just misread it.
There is another version of operator new that does use malloc, but it depends on certain #define. I think it's probably the case most of the time that it uses malloc due to the #define's default behavior, but obviously "operator new[] sits on top of malloc" does not appear to be a universally true statement, even with MSVC.
Quote:Original post by Antheus
Edit: Oh joy.Quote:malloc is required to return memory on a 16-byte boundary.
Now either 32-bit version is broken, or documentation is incorrect, or malloc isn't used by new, or arrays are allocated differently, ....
Uh, did you notice that the page you linked to is in the x64 programming section?
Quote:Original post by SiCrane
Uh, did you notice that the page you linked to is in the x64 programming section?
No, I didn't.
Anyway, for anyone who needs alignment guarantees, there's aligned_malloc or similar. Everyone else shouldn't care, since C++ standard doesn't care either beyond basic guidelines.
I also find too excessive arguments on either side of such topics mostly pointless. This falls strictly into domain of APIs and hardware specific architectures.
Anyone working on such system can, or should, thoroughly RTFM, and then see if language or API makes adequate guarantees for the entire scope of the project (including portability budgets, long-term strategy, developer proficiency and training, etc...) and then use the most suitable approach - even if it means coming up with 200-line UberMacro as only alternative.
Languages, API, all just tools. Going too far to argue over specifics or bugs in certain implementation thereof is similar to standing out in a rainstorm and yelling you are getting wet.
With luck, management or clients will choose or allow better tools for next project, but in practice, one is stuck with what there is. At the end of the day, that is where the good solutions differentiate from the bad.
This topic is closed to new replies.
Advertisement
Popular Topics
Advertisement