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

这个memcpy会导致未定义的行为吗?,c,struct,constants,language-lawyer,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); gcc和clang不会发出任何警告,但会导致修改const限定类型 这个结构看起

根据这一定义:

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);
gcc
clang
不会发出任何警告,但会导致修改const限定类型


这个结构看起来很像被接受的答案中给出的,显然是一致的。我不明白我的示例如何会因此不一致。

成员上的
const
-限定符让编译器假设——在对象初始化后——这些成员不得以任何方式更改,并且可能会相应地优化代码(例如,@Ajay Brahmakshatriya comment)

因此,有必要将初始化阶段与赋值将应用的后续阶段区分开来,即从何时开始,编译器可以假定对象已初始化并具有可依赖的有效类型

我认为你的例子与你所引用的公认答案之间有一个主要区别。在SO应答中,通过
malloc
创建具有常量限定成员类型的目标聚合对象:

ImmutablePoint init = { .x = x, .y = y };
ImmutablePoint *p = malloc(sizeof *p);
memcpy(p, &init, sizeof *p);
根据关于如何访问对象的存储值的规则(参见本部分),目标对象将在执行
memcpy
的过程中第一次获得其有效类型;然后,有效类型是源对象
init
的有效类型,而获取
malloced
的对象上的第一个
memcpy
可以视为初始化。然而,之后修改目标对象的const成员将是UB(我认为即使是第二个
memcpy
也将是UB,但这可能是基于观点的)

6.5表达式

  • 访问其存储值的对象的有效类型是该对象的声明类型(如果有)。87)如果值为 使用memcpy或memmove复制到没有声明类型的对象中, 或被复制为字符类型的数组,则为 该访问和后续访问的已修改对象 “不修改”值是从中删除的对象的有效类型 如果有值,则复制该值。对于对 对象没有声明的类型,则该对象的有效类型为 只是用于访问的左值的类型
  • 87)分配的对象没有声明的类型。

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


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

    请参阅OP的最后一个问题:
    struct
    具有
    const
    成员的
    struct不能通过赋值进行设置,只能通过初始化进行设置(您对
    src
    执行此操作)。
    memcpy
    类似于赋值。从
    struct
    中删除
    const
    ,事情就会好起来。在我看来,结构成员上的const
    并没有那么有用,因为正是您遇到的问题。请注意,
    memcpy
    即使使用
    const
    也不会损害任何东西,但这是一种不好的做法。@CraigEstey它可能会造成伤害。考虑代码-<代码> {Stultvector Foo= {…};浮点A= Fo.x;MimcPy(and Fo,…,siZeof(FoO));int b= fo.x;}。编译器可以重用
    a
    的值来设置
    b
    。这似乎是个好问题,不知道为什么有人否决了它(尽管最后一段没有必要)。我不明白为什么这个问题被否决了;这是一个合理的、精心设计的问题,我不认为这是一个直截了当的回答。谢谢你的回答,这是一个有趣的引用,似乎确实解释了它。但是,我在解释“没有声明类型的对象”时遇到问题。
    p
    是否声明为
    不可变点*
    ?我不这么认为
    p
    是一个与它所指向的对象不同的对象
    p
    具有声明的类型
    ImmutablePoint*
    ,但它指向的对象甚至还没有创建。好的,我不完全清楚“object”在本文中的含义。我还发现在“malloc函数为大小由size指定且其值不确定的对象分配空间”中,我想,它的类型也不确定。我仍然想在这段代码中添加这一点-
    foo(const char*t){char s=*t;某些函数调用(t);char r=*t;}
    ,即使
    t
    标记为指向
    const
    限定的
    char
    ,编译器也无法优化第二次读取。这是因为
    t
    最初可能并不指向
    const
    对象,而且
    某些函数调用
    修改内容是完全有效的。但是这种情况很特殊,因为
    常量
    在结构内部。任何指针的字段都将始终是
    const
    @ReinierTorenbeek,由
    malloc
    分配的对象还没有类型。它们可以通过写入对象来设置有效类型。