0
#include <stdio.h>
int main(void)
{
    char c1 = '0';
    char _Alignas(double) c2 = '0';

    printf("char alignment:   %zd\n", _Alignof(char));
    printf("double alignment: %zd\n", _Alignof(double));
    printf("&c1: %p\n", &c1);
    printf("&c2: %p\n", &c2);

    return 0;
}

Run in my environment, result is:

char alignment: 1
double alignment: 8
&c1: 000000000061FE1F
&c2: 000000000061FE18

Compiled by gcc version 8.1.0 (x86_64-posix-seh-rev0, Built by MinGW-W64 project).

I wonder why the number of bytes between &c2 and &c1 is 7, not 8 (sizeof(double) in my environment)?

phuclv
  • 37,963
  • 15
  • 156
  • 475
Hongyuan
  • 100
  • 6
  • 2
    Because they are aligned? 8-byte alignment means the address will end with three binary 0s, so the last hex digit is always 8 or 0. It has nothing really to do with the number of bytes between variables. – Garr Godfrey Sep 14 '21 at 03:51
  • 1
    You might be thinking of the rule for `struct` and `union` types that their size is always a multiple of their alignment? But there's no such rule for `_Alignas`, which applies to individual objects, not types. The idea behind the former rule is that in an array of `struct`s, the difference in the starting addresses of successive elements must equal the size of the elements. But you can't `_Alignas` the elements of an array, so the issue doesn't arise there. – Nate Eldredge Sep 14 '21 at 05:57

2 Answers2

2

why char _Alignas double size is not 8?

Alignment means the address is a multiple of some value. It has nothing to do with the size of a variable. _Alignas(8) means the address will be a multiple of 8, i.e. ending with 0 or 8 in hexadecimal

I wonder why the bytes between &c2 and &c1 is 7, not 8 (sizeof double in my environment)?

The positions of variables on stack isn't specified. The compiler can freely put c1 before or after c2. The only requirement here is the alignment of c2 which must be a multiple of 8. If c1 is at a multiple of 8 and the compiler chooses to put c2 right after that then 7 bytes of padding will be used. But they can obviously put c1 right before c2 and their addresses will differ by only 1. You can easily see each compiler puts the variables in different positions with different distances

For more details read

phuclv
  • 37,963
  • 15
  • 156
  • 475
1

Alignment determines where the addresses will be, not how much space they will take.

A char only takes up 1 byte, even if it is aligned on an 8 byte boundary. There are 6 unused bytes between c1 and c2.

Often, the alignment and the size will be the same, or the alignment is rounded up to a power of 2. That's because on many architectures it may require multiple FETCH instructions to retrieve from a non-aligned memory address.

In your case, c1 is aligned on a 1-byte boundary, so it is placed at the first available position on the stack.

c2 is aligned on an 8-byte boundary, so it skips over however many bytes are needed until the address is aligned on an 8 byte boundary. This means (address % 8) == 0. If c2 were of type double, it would need to move to the next aligned address, 8 more bytes ahead, but since it is only a char it fits just fine at the first 8-byte boundary. (EDIT: as others have pointed out, the compiler could rearrange the variables, and probably would in that case)

The alignment can be greater or less than the size of the element.

On some architecture, you simply HAD to align on 2 or 4 byte boundaries. The computers simply could not address the "in between bytes". The address lines aren't needed, so you can address 2^16 bytes of memory using only 14 address lines if you align on 4 byte addresses (and always read 4 bytes). That can reduce the size needed for the memory bus.

Garr Godfrey
  • 8,257
  • 2
  • 25
  • 23