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

Posted

技术标签:

【中文标题】重新解释适当对齐的指向具有声明类型的对象的指针【英文标题】:Reinterpreting suitably aligned pointers to object with declared type 【发布时间】:2019-03-20 02:52:09 【问题描述】:

标准允许我们将指向对象类型的指针相互转换,前提是它们适当对齐。 6.3.2.3(p7):

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

标准允许我们将对象表示复制到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)]。所以正式地说,我们不能通过struct contains_64_t * 类型的左值访问buf

但这会很奇怪,因为我们已经适当地对齐了指针和字面上相同的对象表示。我们当然可以声明struct contains_64_t buf[2];,但如果struct 包含可变长度数组

,该解决方案将不起作用

UPD:如果我们假设我们正在使用 GCC 进行编译,那么这样的缓冲区对齐是否就足够了?

【问题讨论】:

对齐不是这里潜在的 UB,通过抗锯齿可能是 struct contains_64_t *c64_ptr = (struct contains_64_t*) buf_2_64t; 的一个问题。 printf("Value = %lu\n", c64_ptr -> value); 肯定是带有 32 位 long 的 UB。 @chux 为什么要转换为适当对齐的指针 UB?或者你的意思是UB是由printf的错误使用引起的?固定。 一些 1) casting 不是 UB 的问题,anti-aliasing UB 可能适用于此。 2) %lu 用于unsigned long,不一定是uint64_t @chux 同意2)。将其替换为在inttypes.h 中定义的PRIu64 @chux 无论如何,如果我们不将指针对齐到堆栈分配的缓冲区,我们将无法转换它。所以 UB 也将出现在 struct contains_64_t *c64_ptr = (struct contains_64_t*) buf_2_64t; 否则标准允许在 6.2.3.2(p7) 进行此类转换。 【参考方案1】:

memcpy() 看起来不错。

c64_ptr -> value 是 UB。

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

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

——与有效类型兼容的类型的限定版本 对象,

——一个类型,它是有符号或无符号类型,对应于 对象的有效类型,

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

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

——一种字符类型。

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

【讨论】:

以上是关于重新解释适当对齐的指向具有声明类型的对象的指针的主要内容,如果未能解决你的问题,请参考以下文章

当指针指向的对象被另一个类的实例删除时重新分配指针

将 void 指针转换为指向类型的指针时使用的术语是啥?

深入浅出理解 . 深拷贝 . 浅拷贝

取消引用指向整个数组的指针

指向具有私有构造函数的类的类成员的指针

类型和声明笔记