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)