【发布时间】:2020-08-13 21:24:52
【问题描述】:
gcc (Ubuntu 7.5.0-3ubuntu1~18.04) 7.5.0
如何以一致的方式将void * 引用没有声明类型的实体与缓存行大小对齐?
我有兴趣用标准解释通用对齐技术的合法性。
我的尝试
void *ptr = //some valid pointer;
void *aligned_ptr = (void *) ((intptr_t) ptr & -64);
(intptr_t) ptr & -64 部分符合要求,因为任何7.20.1.4 N2310:
无符号整数类型,具有任何有效指针指向的属性 void 可以转换为这种类型,然后转换回指向的指针 void ,结果将等于原始指针
未指定将(intptr_t) ptr & -64 转换回void * 具有明确定义的行为。 6.3.2.3/5 提供了一些模糊的信息(emp. mine):
整数可以转换为任何指针类型。除了以前 指定,结果是实现定义的,可能不是 正确对齐,可能不指向被引用的实体 类型,并且可能是陷阱表示。
如果我正确理解“陷阱表示”的概念,那么在这种情况下就不可能拥有它,因为没有声明对象的类型。
我不确定(void *) ((intptr_t) ptr & -64) 是否从标准的角度正确对齐,或者结果不是定义的实现。
UPD:6.2.8 描述
每个有效的对齐值都应该是一个非负整数幂 两个。
由于_Alignof (max_align_t) 在我的实现中是16,所以我认为gcc 没有义务支持64 字节对齐。
【问题讨论】:
-
正如标准所说,除了从指针到整数的转换和返回之外,行为是实现定义的。由于您使用的是 GCC:When casting from pointer to integer and back again, the resulting pointer must reference the same object as the original pointer, otherwise the behavior is undefined。因此,除非您的指针已经与缓存行对齐,否则代码的行为是未定义的。
-
“除了从指针到整数的转换和返回之外,行为是实现定义的” 哎呀。与 C++ 标准混淆。在 C 标准中,即使转换为整数和返回也是实现定义的,除非指针值为 null 或整数为零。
-
您在 sn-p 中尝试执行的操作尚不清楚。你想通过“调整”这样的指针来实现什么?如果它没有指向一个有效的对象,那么它是没有意义的。这似乎是一个 XY 问题。将某些内容与缓存行对齐的正确方法是使用
__attribute__((aligned(64))或类似的编译器指令将其声明为填充到所需的大小。不用说,这不能以通用的非编译器特定的方式进行。没有标准定义的方式来“一致地对齐”要缓存的内容。 -
Re“如果我正确理解了“陷阱表示”的概念,那么在这种情况下就不可能拥有它,因为没有声明对象的类型。”转换为
void *的结果可能是void *类型的陷阱表示。 -
@SomeName 只是因为它是 C11,我不会因为这样一个微不足道的功能而选择 C11。我还假设您在谈论 C99,因为它是最常见的标准版本。
标签: c pointers gcc alignment language-lawyer