此memcpy会导致未定义的行为吗? [英] Could this memcpy result in undefined behavior?

查看:324
本文介绍了此memcpy会导致未定义的行为吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

具有以下定义:

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

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

would the code snippet below possibly result in undefined behavior?

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

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

gcc and clang do not emit any warnings, but it does result in modification of a const-qualified type.

构造看起来很像如何在堆上初始化const成员的答案中给出的构造 ,这显然是一致的.我不明白我的示例将因此如何不符合要求.

The construct looks a lot like the one given in the accepted answer to How to initialize const members of structs on the heap , which apparently is conformant. I do not understand how my example would therefore be non-conformant.

推荐答案

成员上的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.

这篇关于此memcpy会导致未定义的行为吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆