Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ struct memory overhead in clang?

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?

like image 976
byteprelude Avatar asked Oct 19 '22 20:10

byteprelude


2 Answers

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.

like image 125
Puppy Avatar answered Oct 22 '22 13:10

Puppy


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.

like image 32
TonyK Avatar answered Oct 22 '22 13:10

TonyK