且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

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

更新时间:2022-05-27 04:57:42

成员上的const限定符使编译器假定-在初始化对象之后-不得以任何方式更改这些成员,并且可以相应地优化代码(例如,参见@Ajay Brahmakshatriya评论).

The const-qualifiers on members let the compiler assume that - after an object has been initialized - these members must not be altered through any way, and it may optimise code accordingly (cf, for example, @Ajay Brahmakshatriya comment).

因此,必须将 initialization 阶段与随后应用 assignments 的各个阶段区分开,例如,从何时开始,编译器可能会假定对象已初始化并具有一种有效的类型.

So it is essential to distinguish the initialization phase from the subsequent phases where assignments would apply, i.e. from when on may a compiler assume that an object got initialized and has an effective type to rely on.

我认为您的示例与您引用的已接受答案之间存在主要区别.在 SO答案中,具有常量限定成员类型的目标聚合对象是通过malloc创建的:

I think there is a main difference between your example and that in the accepted answer you cited. In this SO answer, the target aggregate object with const-qualified member types is created through malloc:

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

根据有关如何访问对象的存储值的规则(请参见在线c标准草稿),则p目标对象将在执行memcpy的过程中首次获得其有效类型;那么有效类型就是源对象init的类型,并且获得malloced的对象上的第一个memcpy可以看作是初始化.但是,之后修改目标对象的const成员将是UB(我认为即使第二个memcpy也会是UB,但这可能是基于意见的).

According to the rules on how a stored value of an object may be accessed (cf. this part of an online c standard draft), the p-target object will get its effective type the first time in the course of performing memcpy; the effective type is then that of the source object init, and the first memcpy on an object that got malloced can be seen as an initialization. Modifying the target object's const members afterwards, however, would be UB then (I think that even a second memcpy would be UB, but that's probably opinion based).

6.5表达式

  1. 访问其存储值的对象的有效类型是该对象的声明类型(如果有的话).87)... 如果值是 使用memcpy 或memmove复制到没有声明类型的对象中, 或复制为字符类型的数组,然后 修改后的对象,用于该访问以及随后的访问 不修改值是对象的有效类型,从中 该值将被复制(如果有的话).对于所有其他访问 没有声明类型的对象,则该对象的有效类型为 只是用于访问的左值的类型.
  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)分配的对象没有声明的类型.

但是,在您的示例中,目标对象dst通过其定义struct vector dst;已经具有声明的类型.因此,dst成员上的const限定符在应用memcpy之前就已经存在,并且必须将其视为分配而不是初始化.

In your example, however, the target object dst already has a declared type through it's definition struct vector dst;. Hence, the const-qualifiers on dst's members are already in place before the memcpy is applied, and it has to be seen as an assignment rather than an initialization.

因此,在这种情况下,我将投票给UB.

So I'd vote for UB in this case.