0
votes

I have a few questions about memory alignment in C language and how memory is allocated after forcing a variable to be aligned to a certain number of bytes using the _Alignas specifier.

This code shows in output the memory addresses of each declared variable:

#include <stdio.h>

int main(void)
{
       unsigned char dx = 1;
       unsigned char ca  = 1;
       unsigned char cx  = 1;
       unsigned char dz = 1;
       unsigned char cb = 1;
       unsigned char _Alignas(double)  cz = 1;

       char * p_begin = (char *) &cz;
       char * p_end = (char * ) &dx + sizeof(dx);

       printf("Addresses   Value\n");
       for (char * p = p_begin; p < p_end; p++)
       {
              printf("%9p   %6X", p, 0xff & *p);

              if (p == (char *) & dx) printf(" <- dx\n");
              else if (p == (char *) & ca) printf(" <- ca\n");
              else if (p == (char *) & cx) printf(" <- cx\n");
              else if (p == (char *) & dz) printf(" <- dz\n");
              else if (p == (char *) & cb) printf(" <- cb\n");
              else if (p == (char *) & cz) printf(" <- cz\n");
              else printf("\n");
       }

       return 0;
}

On my computer the output is as follows:

Addresses   Value
   28ff08        1 <- cz
   28ff09       FF
   28ff0a       28
   28ff0b        0
   28ff0c       CE
   28ff0d       2A
   28ff0e       40
   28ff0f        1 <- cb
   28ff10        1 <- dz
   28ff11        1 <- cx
   28ff12        1 <- ca
   28ff13        1 <- dx

Process returned 0 (0x0)   execution time : 0.016 s
Press any key to continue.

The only behavior I would have expected to see after forcing the cz variable alignment on 8 bytes is thatcz was allocated to an address whose value is multiple of 8, I would not have expected to see follow cz from the padding. How come this behavior? Also I expected that the number of bytes corresponding to the padding combined with the data size of 1 byte would result in 8, instead the padding occupies 6 bytes for which reason?

1

1 Answers

0
votes

Stacks commonly grow downward. There is no essential reason for this; it is largely simply the result of historical development. A region of memory is allocated for the stack, the stack pointer is set to point to the high end of it, and the main routine of the program is started. As the program needs more stack space, it decreases the stack pointer.

What appears to be happening in your example is that the compiler is assigning space for objects in the order it encounters them. dx is seen first, so it is assigned the next available space on the stack, 0x28ff13. Then ca is seen, and it is assigned 0x28ff12. We see that, as the stack grows, it proceeds from higher addresses (where it started) to lower addresses.

When the compiler gets to cz, for which you have requested eight-byte alignment, the compiler jumps to the next multiple of eight (still in the downward direction), which is 0x28ff08.

Certainly the compiler could have looked at the whole situation (instead of looking at each object one at a time) and put cz at 0x28ff10 and put the other objects around it, using less stack space. If you compile with optimization enabled, the compiler might do that. On the other hand, the compiler might have a requirement on your platform to keep the stack pointer aligned to eight bytes (or more), so rearranging these particular objects would not have saved any stack space anyway.

There are no rules in the C standard about this. The compiler is free to arrange its stack as it chooses.