标准允许我们在适当对齐的情况下将对象类型的指针转换为彼此。 6.3.2.3(p7)
:
指向对象类型的指针可以转换为指向不同对象类型的指针。如果对于引用的类型,结果指针未正确对齐(68),则行为未定义。
标准允许我们将对象表示复制到char[sizeof(the_object_type)]
6.2.6.1(p4)
:
该值可以复制到unsigned char [n]类型的对象中(例如,通过memcpy);生成的字节集称为值的对象表示。
此外,标准明确指出
具有相同对象表示的两个值(除了NaN)比较相等,但是比较相等的值可以具有不同的对象表示。
请考虑以下代码:
struct contains_64_t{
uint64_t value;
};
int main(int args, const char *argv[]){
_Alignas(struct contains_64_t)
char buf_2_64t[2 * sizeof(struct contains_64_t)];
struct contains_64_t c64_1;
c64_1.value = 1;
struct contains_64_t c64_2;
c64_2.value = 2;
memcpy(buf_2_64t, &c64_1, sizeof(c64_1));
memcpy(buf_2_64t + sizeof(c64_1), &c64_2, sizeof(c64_2));
//suitably aligned, ok
struct contains_64_t *c64_ptr = (struct contains_64_t*) buf_2_64t;
printf("Value %"PRIu64"\n", c64_ptr -> value);
}
问题:编写这样的代码是迂腐吗?如果不是,如果这样做我们可能会遇到什么样的问题?
从我看到的,
我们可以将char*
投射到struct contains_64_t
,因为它适当对齐。但问题是声明的buf
类型是char[2 * sizeof(struct contains_64_t)]
。所以正式来说,我们无法通过buf
类型的左值访问struct contains_64_t *
。
但这很奇怪,因为我们有适当的对齐指针和字面上相同的对象表示。当然我们可以声明struct contains_64_t buf[2];
,但是在包含可变长度数组的struct
的情况下解决方案不起作用
UPD:如果我们假设我们正在使用GCC编译,那么这样的缓冲区对齐是否足够?
memcpy()
看起来还不错。
c64_ptr -> value
是UB。
对象的存储值只能由具有以下类型之一的左值表达式访问:
- 与对象的有效类型兼容的类型,
- 与对象的有效类型兼容的类型的限定版本,
- 对应于对象的有效类型的有符号或无符号类型的类型,
- 对应于对象有效类型的限定版本的有符号或无符号类型,
- 聚合或联合类型,其成员中包含上述类型之一(包括递归地,子聚合或包含联合的成员),或者
- 角色类型。
在标准中查找compatible
以完成图片。