1

I am trying to align compound literal to 16 bytes.

I found 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
}
Guillaume D
  • 2,202
  • 2
  • 10
  • 37
  • you see the `.x` ? i mean i don't have tested the macro given in the link i gave above, but i think I understand the mecanism – Guillaume D Jul 22 '22 at 14:36
  • 1
    I see structures in your RHS compound literals but not in any LHS targets. And what is that last code snippet? It's not any sort of C that I know about. – Adrian Mole Jul 22 '22 at 14:37
  • 1
    Messages like "error: invalid initializer" sound about right. You are trying to initialize an array in an invalid way. – Adrian Mole Jul 22 '22 at 14:44
  • ok how would you expain that the link given compiles without any issue? (example with the string) – Guillaume D Jul 22 '22 at 14:46
  • 1
    Guillaume D, this is interesting, but might be an XY problem. Why do you want "align compound literal to 16 "? "control the alignment of some data block inside a structure declaration," is unclear. – chux - Reinstate Monica Aug 04 '22 at 11:50
  • it was indeed a XY issue fixed with in this [question](https://stackoverflow.com/questions/73137517/could-array-and-structures-be-initialized-in-a-different-way) (even if the question is not resolved yet). I thought we needed a 16 bytes alignment because of some hardware IP are writing 16 bytes blocks – Guillaume D Aug 04 '22 at 12:27
  • 1
    @GuillaumeD Hmm, I'll review link question later today. – chux - Reinstate Monica Aug 04 '22 at 12:49

2 Answers2

1

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

ikegami
  • 367,544
  • 15
  • 269
  • 518
  • ok how would you expain that the link given compiles without any issue? (example with the string) – Guillaume D Jul 22 '22 at 14:48
  • Are you referring to `char *u = ALIGNED_STRING("agsdas");`? As stated in my answer, the alignment `u` is strictly based on the fact that it's a `char*`. `ALIGNED_STRING("agsdas")` does not affect the alignment of `u`. – ikegami Jul 22 '22 at 14:49
  • https://stackoverflow.com/a/34797534/10734452 so it is not working? – Guillaume D Jul 22 '22 at 14:50
  • So yes? _______ – ikegami Jul 22 '22 at 14:51
  • we can see that it handles the aligment – Guillaume D Jul 22 '22 at 14:51
  • Not of `u`, though. It change the alignment of some anonymous `char[]` – ikegami Jul 22 '22 at 14:51
  • That's not true. Your question doesn't have any pointers. Your question is about the alignment of a variable and its components. `u` is the variable in the linked snippet, so `u` in that post is the parallel to `foo` in your post. – ikegami Jul 22 '22 at 14:56
  • 1
    ok, i didn't mentionned that the foo struct contains pointers – Guillaume D Jul 22 '22 at 15:25
  • Re "*i didn't mentioned that the foo struct contains pointers*", It's not that you didn't *mention* pointers to anon objects, it's that you did not *use* pointers (to anon object or anything), and the problem is directly related to that. See updated answer. – ikegami Jul 22 '22 at 15:39
1

At least these issues:

  • OP's macro array sizing was wrong.

    // uint32_t x[sizeof ((uint32_t[]){__VA_ARGS__})]
    uint32_t x[sizeof ((uint32_t[]){__VA_ARGS__}) / sizeof(uint32_t)]
    
  • Add { }

    // OP's
    #define ALIGNED_U32(...)  (struct { _Alignas(16) uint32_t x[sizeof ((uint32_t[]){ __VA_ARGS__})                 ]; }){   __VA_ARGS__   }.x
    // Suggested fix
    #define ALIGNED_U32(...)  (struct { _Alignas(16) uint32_t x[sizeof ((uint32_t[]){ __VA_ARGS__})/sizeof(uint32_t)]; }){ { __VA_ARGS__ } }.x
    

Sample usage

#define ALIGNED_U32(...)  (struct { _Alignas(16) uint32_t x[ \
    sizeof ((uint32_t[]){ __VA_ARGS__ })/sizeof(uint32_t) \
    ]; }) { .x = { __VA_ARGS__ } }.x

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

s_t foo = { //
    .foo1 = ALIGNED_U32(1, 2, 3), //
    .foo2 = ALIGNED_U32(2, 2), //
    .foo3 = (uint32_t[]) {1, 2, 3}, // might be not 16-bytes-aligned
    .foo4 = (uint32_t[]) {2, 2},  // might be not 16-bytes-aligned
};
chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256