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

时间:2019-03-20 02:52:10

标签: c language-lawyer type-punning

如果适当对齐,则Standard允许我们将指向对象类型的指针彼此强制转换。 6.3.2.3(p7)

  

指向对象类型的指针可能会转换为指向对象类型的指针   不同的对象类型。如果结果指针不正确   对于引用类型,该行为是不确定的。

该标准允许我们将对象表示形式复制到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进行编译,那么进行这种缓冲区对齐就足够了吗?

1 个答案:

答案 0 :(得分:2)

memcpy()看起来不错。

c64_ptr -> value是UB。

  

一个对象的存储值只能由左值访问   具有以下类型之一的表达式:

     

-与对象的有效类型兼容的类型,

     

-与有效类型兼容的合格版本   对象

     

-一种类型,它是与   对象的有效类型,

     

-一种类型,它是对应于a的有符号或无符号类型   有效类型的对象的限定版本,

     

-包含上述类型之一的集合或联合类型   其成员之间的类型(包括,递归地,   子集合或包含的并集),或

     

-字符类型。

在标准中查找compatible以完成图片。