1

I am using a couple of online compilers to test a sample program (for reference, the one in ideone and the one in tutorialspoint) The program is:

#include <stdio.h>
#include <stdint.h> 

uint8_t Array[5]__attribute((aligned(32)));
uint8_t Array2[5]__attribute((aligned(8)));
static uint8_t Array3[5]__attribute((aligned(8)));
static uint8_t Array4[5]__attribute((section("bbs"),aligned(32)));


int main()
{
    printf("%p %p %p %p %p \n", &Array[0], &Array[1], &Array[2], &Array[3],&Array[4]);
    printf("%p %p %p %p %p \n", &Array2[0], &Array2[1], &Array2[2], &Array2[3],&Array2[4]);
    printf("%p %p %p %p %p \n", &Array3[0], &Array3[1], &Array3[2], &Array3[3],&Array3[4]);
    printf("%p %p %p %p %p \n", &Array4[0], &Array4[1], &Array4[2], &Array4[3],&Array4[4]);

    return 0;
}

The results are for example

0x2aff9175b0a0 0x2aff9175b0a1 0x2aff9175b0a2 0x2aff9175b0a3 0x2aff9175b0a4 
0x2aff9175b080 0x2aff9175b081 0x2aff9175b082 0x2aff9175b083 0x2aff9175b084 
0x2aff9175b068 0x2aff9175b069 0x2aff9175b06a 0x2aff9175b06b 0x2aff9175b06c 
0x2aff9175b040 0x2aff9175b041 0x2aff9175b042 0x2aff9175b043 0x2aff9175b044 

I can see that aligned does not seem to have an effect on where the array elements are stored. What does aligned actually do? (I am asking after reading the explanation in here which I didn't quite catch.)

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
KansaiRobot
  • 7,564
  • 11
  • 71
  • 150
  • 1
    Nitpick: You must cast the arguments to `void *`. – Sourav Ghosh Jun 21 '17 at 06:21
  • 2
    Arrays are *always* stored contiguously. You can only influence the alignment of the array's start address with this attribute. Eg `Array` will *start* at an address divisable by 32. –  Jun 21 '17 at 06:29
  • I see. Why would that be important? And how can I see that in the example results I posted above? – KansaiRobot Jun 21 '17 at 06:31
  • Try to divide the first address printed by 32. For why this *could* be important: e.g. interfacing with DMA hardware requiring that, or some performance consideration -- this is a quite broad question. –  Jun 21 '17 at 06:35
  • It's an extension anyways and writing *application* code, you'll probably never need it. –  Jun 21 '17 at 06:36
  • The same thing as _Alignof. – Petr Skocik Jun 21 '17 at 07:00

2 Answers2

4

The alignment attribute is described here in the GNU Compiler documentation.

It said about it:

This attribute specifies a minimum alignment for the variable or structure field, measured in bytes.

That means you will set the minimum alignment but for the beginning of the array. The rest of the array is guaranteed to be contiguous, that means the addresses that follows are dependent on the type in your example uint8_t. If the array start address is at 0x2aff9175b0a0 like in your case the next address must be 1 byte after it at 0x2aff9175b0a1 (0xa0 --> 0xa1).

To explain your example:

Alignment 32 beginning at: 0x2aff9175b0a0 --> 0xa0 = 160 = 32 * 5
Alignment 8  beginning at: 0x2aff9175b080 --> 0x80 = 128 = 8  * 16
Alignment 8  beginning at: 0x2aff9175b068 --> 0x68 = 104 = 8  * 13
Alignment 32 beginning at: 0x2aff9175b040 --> 0x40 = 64  = 32 * 2

As you see the alignment of the beginning of the array is as you want it. You could increase the alignment and watch the addresses again. But also consider:

Note that the effectiveness of aligned attributes may be limited by inherent limitations in your linker. On many systems, the linker is only able to arrange for variables to be aligned up to a certain maximum alignment.

Further if you use printf() to print the addresses with %p, then also cast the addresses to a void*, because the pointer types doesn't need to have the same representations except for some of them. That fact is also explained here.

Andre Kampling
  • 5,476
  • 2
  • 20
  • 47
2

You might get a better picture of what's going on with slightly different sample code. Here's an adaptation of your program. There's no virtue in printing the addresses of elements indexed by [1] etc; those positions are 100% controlled by the type (uint8_t) and the start address of the array.

#include <stdio.h>
#include <stdint.h> 

uint8_t Array1[5]__attribute((aligned(32)));
uint8_t Array2[5]__attribute((aligned(8)));
static uint8_t Array3[5]__attribute((aligned(8)));
static uint8_t Array4[5]__attribute((aligned(32)));

uint16_t u16_a1[3];
uint16_t u16_a2[3];
uint16_t u16_a3[3];

uint16_t u16_a4[3] __attribute((aligned(32)));
uint16_t u16_a5[3] __attribute((aligned(32)));
uint16_t u16_a6[3] __attribute((aligned(32)));

int main(void)
{
    printf("%s: %p\n", "Array1", (void *)Array1);
    printf("%s: %p\n", "Array2", (void *)Array2);
    printf("%s: %p\n", "Array3", (void *)Array3);
    printf("%s: %p\n", "Array4", (void *)Array4);

    printf("%s: %p\n", "u16_a1", (void *)u16_a1);
    printf("%s: %p\n", "u16_a2", (void *)u16_a2);
    printf("%s: %p\n", "u16_a3", (void *)u16_a3);
    printf("%s: %p\n", "u16_a4", (void *)u16_a4);
    printf("%s: %p\n", "u16_a5", (void *)u16_a5);
    printf("%s: %p\n", "u16_a6", (void *)u16_a6);

    return 0;
}

I had to remove the section(bbs), directive; the Mac linker didn't accept it. I also renamed Array to Array1 for self-consistency with the rest of the array names.

The output I got was:

Array1: 0x10a1fc040
Array2: 0x10a1fc048
Array3: 0x10a1fc028
Array4: 0x10a1fc020
u16_a1: 0x10a1fc04e
u16_a2: 0x10a1fc054
u16_a3: 0x10a1fc05a
u16_a4: 0x10a1fc060
u16_a5: 0x10a1fc080
u16_a6: 0x10a1fc0a0

Note that the address of Array1 is aligned on a 32-byte boundary, and Array2 is on an 8 byte boundary just after Array1. Similarly, Array3 and Array4 are located on appropriately aligned boundaries. (Of course, a 32-byte boundary is an address which ends z0 in hex, where z is an even number. An 8-byte boundary is an address that ends in 8 or 0 in hex.)

The u16_a1 to u16_a3 arrays are not alignment constrained. They're 6 bytes each, and the three addresses differ by 6 bytes.

By contrast, the u16_a4 to u16_a6 arrays are constrained to a 32-byte boundary. As you can see, their addresses differ from each other by 32 bytes, and each is located on a 32-bit boundary, whereas if they were unconstrained, they'd be much closer together. You might note that u16_a3 and u16_a4 happen to be contiguous in memory — pure chance, not planning on my part.

You can adapt this code to play with other types and alignments.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278