Reputation: 77
Is there a per-struct memory overhead in clang? Usually the size of a struct is just the total size of all of its members. But this doesn't seem to be the case in clang:
#include <iostream>
using namespace std;
struct Obj {
int x;
int y;
};
int main() {
int a = 42;
int b = 43;
Obj obj = {100, 101};
int c = 44;
cout << *(&a - 0) << endl; // 42
cout << *(&a - 1) << endl; // 43
cout << *(&a - 2) << endl; // On clang this prints garbage value instead of 101, how strange...
cout << *(&a - 3) << endl; // 101
cout << *(&a - 4) << endl; // 100
cout << *(&a - 5) << endl; // 44
return 0;
}
I compiled with clang++ program.cpp
, no optimization. Version:
Ubuntu clang version 3.4-1ubuntu3 (tags/RELEASE_34/final) (based on LLVM 3.4)
Target: x86_64-pc-linux-gnu
Thread model: posix
The memory location at (&a - 2)
doesn't seem to be used at all. I inserted the following code between the declaration of int a
and int b
:
*(&a - 2) = -1234;
This will later print -1234
instead of a garbage value on *(&a - 2)
, indicating that clang didn't write to this value after creating Obj obj
, which makes me wonder why clang reserved it in the first place.
On gcc this behaves differently. First, the stack appears to grow toward higher memory addresses on gcc on my machine. Also, gcc took it upon itself to place the variable c
right after b
, so the it looks like this:
cout << *(&a + 0) << endl; // 42
cout << *(&a + 1) << endl; // 43
cout << *(&a + 2) << endl; // 44 gcc moved c here even without optimization
cout << *(&a + 3) << endl; // 100
cout << *(&a + 4) << endl; // 101
Compiled with g++ program.cpp
. Version:
g++ (Ubuntu 4.8.2-19ubuntu1) 4.8.2
Same behavour when I ported the program to C. Everything is run on a 64-bit Linux Mint 17.1. Can someone explain whether there is a greater purpose to clang's waste of 4 bytes of memory?
Upvotes: 5
Views: 1212
Reputation: 79487
There is alignment, of course. It's 4 bytes on 32-bit programs, I don't know about 64-bit.
There is a #pragma
for that, actually:
#pragma pack(push) /* push current alignment to stack */
#pragma pack(1) /* set alignment to 1 byte boundary */
struct MyPackedData
{
char Data1;
long Data2;
char Data3;
};
#pragma pack(pop) /* restore original alignment from stack */
That way when you have an array of structs, accessing them won't constantly generate out-of-alignment exceptions that need to be handled. See What's the actual effect of successful unaligned accesses on x86?
See https://en.wikipedia.org/wiki/Data_structure_alignment for more info.
I have no idea if this is the case for you, because 2 ints should be aligned anyway, but maybe they're not on 64-bit architectures? Ints are 32-bit even for 64-bit CPUs, while the alignment probably is 64-bit, or 8 bytes.
Of course, since the struct is on the stack, the other variables and their alignment also matter.
Also see struct alignment C/C++, and Memory alignment in C-structs
Upvotes: -1
Reputation: 166
Here's what the compiler is allowed to and not allowed to: The compiler is not allowed to pad before the first member. The compiler is not allowed to reorder the members (though gcc/clang supports some command line flag that explicitly allows that).
The compiler is allowed to pad between any members, and most will pad such that all members are naturally aligned (&member % sizeof(member) == 0):
struct foo {
char a;
int b; // pad 3 bytes before b
}
Compiler is also allowed to pad after the last member. Most compilers will pad such that sizeof(T) % sizeof(largest member of T) == 0, like this:
struct foo {
int a;
char b; // pad 3 bytes after b
}
For stack variables (your a, b, obj and c), the compiler is free to reorder and pad like it wants.
Size of member types and wether or not to utilize packing depends on architecture, compiler version and compiler flags, hence the different results people get running your code.
Upvotes: 1
Reputation: 17114
Clang is simply aligning the structure on an 8-byte boundary, so that it can be more efficiently copied. GCC does it too, but GCC's stack layout is different, so the structure is already aligned.
Upvotes: 1
Reputation: 146940
The test you have run has nothing to do with the struct and everything to do with the stack. It's undefined behaviour to start reading from random stack memory locations, the compiler has every right to do whatever it wants with them. With no optimizations, it's obvious that the compiler won't bother making efficient use of them. Nobody cares about a few bytes lost without optimizations.
Furthermore, struct and class layout is defined by a standard which is common to both GCC and Clang, so I assure you that they are identical (modulo bugs) on Linux.
Essentially, you are assuming that the compiler is laying out your local variables in exact order on the stack with nothing else there, but there's absolutely no reason to believe that this is true. The compiler has no obligation to lay out the stack in any way.
Upvotes: 2