Monday, July 25, 2022

[SOLVED] How to get a specific aligment for compound literals?

Issue

I am trying to align compound literal to 16 bytes.

I found href="https://stackoverflow.com/questions/34796571/c-aligning-string-literals-for-a-specific-use-case">this

which is :

#define ALIGNED_STRING(S)  (struct { _Alignas(16) char s[sizeof S]; }){ S }.s
char *u = ALIGNED_STRING("agsdas");

which compiles.

and tried to apply it to uint32_t.

I tried this so far with gcc.

#define BLOCK_ALIGNED_U32(...)  (struct { _Alignas(16) uint32_t x[sizeof ((uint32_t[]){__VA_ARGS__})]; }){ __VA_ARGS__ }.x
uint32_t toto[] = BLOCK_ALIGNED_U32(0x11111111, 0x22222222);

and even:

uint32_t tata[] = (struct { uint32_t __attribute__((aligned(16))) x[2]; }){.x = {0x11111111, 0x22222222}}.x;

but it gives me error : invalid initializer

What am I doing wrong / missing?

note: I am doing this because I want to control the aligment of some data block inside a structure declaration, like this:

struct
{
    uint32_t* foo1;
    uint32_t* foo2;
    uint32_t* foo3;
    uint32_t* foo4;
}s_t;

s_t foo[]=
{
   .foo1 = BLOCK_ALIGNED_U32(1,2,3),
   .foo2 = BLOCK_ALIGNED_U32(2,2),
   .foo3 = (uint32_t[]){1,2,3},//could be not 16-bytes-aligned
   .foo4 = (uint32_t[]){2,2},//could be not 16-bytes-aligned
}

Solution

Alignment is determined by the type of the object and directives associated with the object itself. It isn't determined by the value from which it is initialized.

In other words, there's nothing you can place on the right of uint32_t foo[] = that will affect how the array or individual elements of the array are aligned.


Let's compare.

In the linked post

char *u = ALIGNED_STRING("agsdas");

This produces two objects.

u                        <anon>
alignment = char*        alignment = 16
+----------------+       +---+---+---+-...-+
|         -------------->| a | g | s | ... |
+----------------+       +---+---+---+-...-+

As you can see, ALIGNED_STRING has no effect on the alignment of the variable (u), just the alignment of the anon object to which u will point.

In your post

uint32_t foo[] = ...;

This produces a single object.

foo
alignment = uint32_t[] = uint32_t
+----------------+
|                |
+----------------+
|                |
+----------------+
|                |
⋮                ⋮
|                |
+----------------+

If you had an array of pointers to uint32_t, you could align those uint32_t as you wish.

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

int main( void ){
   _Alignas( 16 ) uint32_t i1 = 1;
   _Alignas( 16 ) uint32_t i2 = 2;
                  uint32_t i3 = 3;
                  uint32_t i4 = 4;

   uint32_t *ptrs[] = {
      &i1,
      &i2,
      &i3,
      &i4,
   };

   size_t n = sizeof(ptrs)/sizeof(*ptrs);

   for ( size_t i=0; i<n; ++i ) {
      uint32_t *ptr = ptrs[i];
      printf( "%p %" PRIu32 "\n", (void *)ptr, *ptr );
   }
}

We can even make those object anonymous. Anonymous objects can be created using the ( type ){ initializer body } syntax, and can use _Alignas as part of the type to align the object.

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

#define ALIGNED_UINT32( S, I ) ( ( _Alignas( S ) uint32_t ){ I } )
#define ANON_UINT32(       I ) ( (               uint32_t ){ I } )

int main( void ){
   uint32_t *ptrs[] = {
      &ALIGNED_UINT32( 16, 1 ),
      &ALIGNED_UINT32( 16, 2 ),
      &ANON_UINT32(        3 ),
      &ANON_UINT32(        4 ),
   };

   size_t n = sizeof(ptrs)/sizeof(*ptrs);

   for ( size_t i=0; i<n; ++i ) {
      uint32_t *ptr = ptrs[i];
      printf( "%p %" PRIu32 "\n", (void *)ptr, *ptr );
   }
}

Both of the above produce five objects.

ptrs
alignment = uint32_t*
+----------------+                   +---+---+---+---+ i1/<anon>
|         -------------------------->|             1 | alignment = 16
+----------------+                   +---+---+---+---+
|         ----------------------+
+----------------+              |    +---+---+---+---+ i2/<anon>
|         -----------------+    +--->|             2 | alignment = 16
+----------------+         |         +---+---+---+---+
|         ------------+    |
+----------------+    |    |         +---+---+---+---+ i3/<anon>
                      |    +-------->|             3 | alignment = uint32_t
                      |              +---+---+---+---+
                      |
                      |              +---+---+---+---+ i4/<anon>
                      +------------->|             4 | alignment = uint32_t
                                     +---+---+---+---+

Sample run:

0x7ffe29b31b30 1
0x7ffe29b31b20 2
0x7ffe29b31b1c 3
0x7ffe29b31b18 4

Demo on Compiler Explorer



Answered By - ikegami
Answer Checked By - Willingham (WPSolving Volunteer)