I have a C program compiled with gcc on Ubuntu x86. This is a function I am calling from main
void addme()
{
long a = 5;
char c = '3';
long array[3];
array[0] = 2;
array[1] = 4;
array[2] = 8;
}
If I break at last line, and debug/inspect this is what I get
(gdb) print &a
$5 = (long *) 0xbffff04c
(gdb) print &c
$6 = 0xbffff04b "3\005"
(gdb) print &array
$7 = (long (*)[3]) 0xbffff03c
(gdb) x 0xbffff03c
0xbffff03c: 0x00000002
(gdb) x 0xbffff040
0xbffff040: 0x00000004
(gdb) x 0xbffff044
0xbffff044: 0x00000008
(gdb) x 0xbffff04c
0xbffff04c: 0x00000005
Why is 0xbffff048, 0xbffff049, 0xbffff04a and 0xbffff04b reserved for the char c
when only 0xbffff04b is required to store a char?
Also what does this notation "3\005"
mean?
On the other hand if my method is as below, there is no padding for the character with three extra bytes of storage
void addme()
{
long a = 5;
char c = '3';
char line[9];
char d = '4';
}
This is how memory allocation looks like for these variables (skipping the leading part of the address)
a - f04c
c - f04b
d - f04a
line - f041, f042, f043, f044, f045, f046, f047, f048, f049
Also not sure why d
was hoisted above line
in memory reservation. I assume because it wasn't initialized, it goes to a different region in stack than initialized variables?
This is called alignment. Objects are aligned to multiples of specific integers (usually 4 or 8 in case of long
) for fast access.
In general, you don't need to worry too much about the placement in C++, since the language specification usually enables the compiler to choose the most efficient (in terms of your orientation of optimization) way to store objects, which is usually the case.
Every object type has the property called alignment requirement, which is an integer value (of type
std::size_t
, always a power of2
) representing the number of bytes between successive addresses at which objects of this type can be allocated. The alignment requirement of a type can be queried withalignof
orstd::alignment_of
. The pointer alignment functionstd::align
can be used to obtain a suitably-aligned pointer within some buffer, andstd::aligned_storage
can be used to obtain suitably-aligned storage.Each object type imposes its alignment requirement on every object of that type; stricter alignment (with larger alignment requirement) can be requested using
alignas
.In order to satisfy alignment requirements of all non-static members of a class, padding may be inserted after some of its members.
(cppreference)
Regarding your second question, @prl gives the answer:
Because
c
is achar
,&c
is achar *
, so gdb prints it as a string. The first character of the string is '3', the value ofc
. The next character is 5, the low byte ofa
, which gdb prints in octal escape notation. Escape sequences in C on Wikipedia – prl 1024 min ago
Why did the pad disappear when you declare char
s after the char
? Because in this case, char
's alignment appears to be 1, which means no padding is needed. On the other hand, long
's appears to be 4, so there has to be a 4-byte space, in which the char
is placed.
I assume because it wasn't initialized, it goes to a different region in stack than initialized variables?
Not really. Whether an variable is initialized (in general) does not affect its placement, only that it has an indeterminate value. On the other hand, the compiler is free to place the objects in memory the way it likes. In practice, compilers "enjoy" implementations that lead to efficiency, both in memory and time.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With