C 重新解释指向具有声明类型的对象的适当对齐指针

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

该标准允许我们将指向对象类型的指针相互转换,如果它们适当对齐的话<代码>6.3.2.3(第7页):

指向对象类型的指针可以转换为指向对象类型的指针 不同的对象类型。如果生成的指针不正确 aligned68)对于引用的类型,行为未定义

该标准允许我们将对象表示复制到
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)
处进行这种转换。