gcc 如何获得复合文字的特定对齐方式?

a7qyws3x  于 2022-11-13  发布在  其他
关注(0)|答案(2)|浏览(135)

我正在尝试将复合文字对齐到16个字节。
我找到了this
其为:

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

编译。
并尝试将其应用于uint32_t。
到目前为止,我用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);

甚至:

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

但它给了我error : invalid initializer
我做错了什么/遗漏了什么?
注意:我这样做是因为我想控制结构声明中某个数据块的对齐,如下所示:

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
}
vshtjzan

vshtjzan1#

至少这些问题:

  • OP的宏数组大小错误。
// uint32_t x[sizeof ((uint32_t[]){__VA_ARGS__})]
uint32_t x[sizeof ((uint32_t[]){__VA_ARGS__}) / sizeof(uint32_t)]
  • { }相加
// 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

样本使用

#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
};
oxf4rvwz

oxf4rvwz2#

对齐方式由对象的类型和与对象本身相关联的指令决定,而不是由初始化它的值决定。
换句话说,在uint32_t foo[] =的右边不能放置任何会影响数组或数组中各个元素对齐方式的东西。
我们来比较一下。

在链接的帖子中

char *u = ALIGNED_STRING("agsdas");

这会产生两个对象。

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

正如您所看到的,ALIGNED_STRING对变量(u)的对齐没有影响,只是对u将要指向的anon对象的对齐有影响。

在你的岗位上

uint32_t foo[] = ...;

这会产生单一对象。

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

如果你有一个指向uint32_t的指针数组,你可以根据自己的意愿对齐这些uint32_t

#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 );
   }
}

匿名对象可以使用( type ){ initializer body }语法来创建,也可以使用_Alignas作为类型的一部分来对齐对象。

#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 );
   }
}

以上两种方法都会产生五个对象。

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
                                     +---+---+---+---+

样品运行:

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

编译器资源管理器上的Demo

相关问题