这个 memcpy 会导致未定义的行为吗?

标签 c struct constants language-lawyer

有了这个定义:

struct vector {
    const float x;
    const float y;
};

下面的代码片段是否会导致未定义的行为?

struct vector src = {.x=1.0, .y=1.0};
struct vector dst;
void *dstPtr = &dst;    
memcpy(dstPtr, &src, sizeof dst);

gccclang 不会发出任何警告,但会导致对 const 限定类型的修改。

该构造看起来很像对 How to initialize const members of structs on the heap 的已接受答案中给出的构造,这显然是一致的。我不明白我的示例为何会因此不符合标准。

最佳答案

成员上的 const 限定符让编译器假定 - 在一个对象被初始化后 - 这些成员不能以任何方式改变,并且它可以相应地优化代码(例如,cf ,@Ajay Brahmakshatriya 评论)。

因此,必须将初始化阶段与应用赋值的后续阶段区分开来,即从何时开始,编译器可能会假定对象已初始化并具有一种值得信赖的有效类型。

我认为您的示例与您引用的公认答案之间存在主要区别。在 this所以回答,具有 const 限定成员类型的目标聚合对象是通过 malloc 创建的:

ImmutablePoint init = { .x = x, .y = y };
ImmutablePoint *p = malloc(sizeof *p);
memcpy(p, &init, sizeof *p);

根据如何访问对象的存储值的规则(参见 an online c standard draft 的这一部分),p-target 对象将在第一次获得其有效类型memcpy执行过程;有效类型是源对象 init 的类型,得到 malloced 的对象上的第一个 memcpy 可以看作是初始化。然而,之后修改目标对象的 const 成员将是 UB(我认为即使是第二个 memcpy 也会是 UB,但这可能是基于意见的)。

6.5 Expressions

  1. The effective type of an object for an access to its stored value is the declared type of the object, if any.87) ... If a value is copied into an object having no declared type using memcpy or memmove, or is copied as an array of character type, then the effective type of the modified object for that access and for subsequent accesses that do not modify the value is the effective type of the object from which the value is copied, if it has one. For all other accesses to an object having no declared type, the effective type of the object is simply the type of the lvalue used for the access.

87) Allocated objects have no declared type.

但是,在您的示例中,目标对象 dst 已经通过其定义 struct vector dst; 声明了类型。因此,dst 成员上的 const 限定符在应用 memcpy 之前就已经存在,它必须被视为赋值而不是初始化。

所以在这种情况下我会投票给 UB。

关于这个 memcpy 会导致未定义的行为吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54244005/

相关文章:

flutter - Dart 编译器是否能够推断出 const 构造函数的用法?

c++ - 在代码中声明常量或使用数字

c - 设置输出端口高低 C

inheritance - 如何避免具有语义相同字段/属性的不同结构的代码重复?

c - 如何在 c 中 exec() 我的程序?

c++ - 如何引用结构存储的变量,该结构也是其他结构的一部分

c - 如何将(深层)整个结构及其所有成员复制到另一个结构中? (经过编辑以使目标更容易实现)

c - 将 +/- 字母等级定义为常量。 C

c - 4位十进制到16位二进制转换码

c - 如何循环遍历头文件中声明的数组?