struct {
uint64_t a; char z[120];
} b;
...
struct buffer_with_alignment_requirement* c = (struct buffer_w*)&b;
c->start_using_it;
如果没有第一个成员a
,我们可能会在访问缓冲区中的字段时崩溃。简单地添加这样的成员以强制对齐整个结构足够严格是否可移植且正确?
这不是关于指针别名的问题,只是关于b
堆栈上的地址是否总是八字节对齐。
struct {
uint64_t a; char z[120];
} b;
...
struct buffer_with_alignment_requirement* c = (struct buffer_w*)&b;
c->start_using_it;
如果没有第一个成员a
,我们可能会在访问缓冲区中的字段时崩溃。简单地添加这样的成员以强制对齐整个结构足够严格是否可移植且正确?
这不是关于指针别名的问题,只是关于b
堆栈上的地址是否总是八字节对齐。
精确宽度整数类型(如果存在)(7.20.1.1p3)没有任何特定的对齐要求,除了它们应该至少与(6.2.8p2-4)一样对齐char
并且不超过max_align_t
(6.2.8p2-4)对齐。甚至没有任何要求对齐应该遵循整数转换等级,当然相应的有符号和无符号类型应该具有相同的对齐(6.2.5p6)。
如果您想要特定的对齐方式,请使用对齐说明符:
#include <stdalign.h>
struct alignas(8) {
char z[120];
} b;
但是,大概考虑到您对访问字段的描述,您真正想要的是使缓冲区与缓冲区中可能存在的最对齐类型对齐。为此,C11 提供了max_align_t
;在较旧的编译器中,您可以max_align_t
使用标准类型的联合进行模拟:
typedef union {
char c;
short s;
int i;
long l;
long long ll; // if available
float f;
double d;
long double ld; // if available
void *p;
void (*fun)();
} max_align_t;
不,C 标准让编译器自行决定对齐。
在实践中,许多编译器会将 struct 对齐 8 字节对齐,但它们不是必须这样做的。
这取决于您所说的对齐是什么意思。如果你愿意(uintptr_t)&b % 8 == 0
,没有可移植的方法来获得它,因为从指针到整数的转换是实现定义的,不需要任何理智、自然的映射。
如果您想要的只是让缓冲区充分对齐以便使用 type 进行访问uint64_t
,那么您的解决方案效果很好。但是你为什么不只使用(可能是一个数组) type struct buffer_with_alignment_requirement
,而不是丑陋的联合黑客呢?换句话说,只需为缓冲区提供您想要访问它的正确类型即可。您可以将指向任何类型的指针传递给read
、fread
、revc
等以及您可能用于写入缓冲区的其他函数,即使您将其传递给需要类型为char *
或的缓冲区指针的函数unsigned char *
,您通过时可以施放;这个演员表是完全明确和有效的。