C 重新解释指向具有声明类型的对象的适当对齐指针
该标准允许我们将指向对象类型的指针相互转换,如果它们适当对齐的话<代码>6.3.2.3(第7页): 指向对象类型的指针可以转换为指向对象类型的指针 不同的对象类型。如果生成的指针不正确 aligned68)对于引用的类型,行为未定义 该标准允许我们将对象表示复制到C 重新解释指向具有声明类型的对象的适当对齐指针,c,language-lawyer,type-punning,C,Language Lawyer,Type Punning,该标准允许我们将指向对象类型的指针相互转换,如果它们适当对齐的话6.3.2.3(第7页): 指向对象类型的指针可以转换为指向对象类型的指针 不同的对象类型。如果生成的指针不正确 aligned68)对于引用的类型,行为未定义 该标准允许我们将对象表示复制到char[sizeof(对象类型)]6.2.6.1(p4): 该值可以复制到unsigned char[n]类型的对象中 (例如,由memcpy提供);产生的字节集称为对象 值的表示 此外,该标准明确规定: 具有相同对象表示形式的两个值(非Na
char[sizeof(对象类型)]
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\u 64\u t
,因为它是适当对齐的。但问题是buf
的声明类型是char[2*sizeof(struct contains_64_t)]
。因此,从形式上讲,我们不能通过struct contains*类型的左值访问buf
但这会很奇怪,因为我们有适当对齐的指针和完全相同的对象表示。当然我们可以声明struct包含buf[2]
,但如果struct
包含可变长度数组
UPD:如果我们假设使用GCC进行编译,那么这样的缓冲区对齐就足够了吗?memcpy()
c64\u ptr->value
为UB
对象的存储值只能由左值访问
具有以下类型之一的表达式:
-与对象的有效类型兼容的类型
-与有效类型兼容的类型的限定版本
对象,
-一种类型,它是与
对象的有效类型
-一种类型,它是与
对象的有效类型的限定版本
-一种集合或联合类型,包括上述其中一种
其成员之间的类型(递归地包括
子集合体或包含的联合体),或
-字符类型
在标准中查找compatible
,以完成图片。这里对齐不是潜在的UB,通过消除混叠可能与struct contains_64_t*c64_ptr=(struct contains_64_t*)buf_2_64t有关代码><代码>printf(“值=%lu\n”,c64_ptr->Value)
当然是32位长的UB
@chux为什么要将其转换为一个适当对齐的指针UB?或者您的意思是UB是由不正确使用printf
引起的?修正了。有些演员不是UB关心的问题,UB可以在这里申请。2) %lu
表示无符号长
,不一定uint64\u t
@chux同意2)
。将其替换为inttypes.h
@chux中定义的PRIu64
,如果指针未与堆栈分配的缓冲区对齐,则无法转换它。因此UB也将出现在struct contains_64_t*c64_ptr=(struct contains_64_t*)buf_2_64t代码>否则,标准允许在6.2.3.2(p7)
处进行这种转换。