将结构变量分配给自身(通过指针取消引用)定义的行为吗?

Mic*_*nes 4 c struct pointers memcpy

如果两个指针指向同一个结构变量,是否定义了将一个取消引用的指针分配给另一个指针的行为?

struct Struct {
    int member;
};

int main() {
    struct Struct s, *p1, *p2;
    s.member = 1234;
    p1 = p2 = &s;
    *p1 = *p2; // is this allowed?
}
Run Code Online (Sandbox Code Playgroud)

我主要问这个问题,因为在这篇 SO 帖子这篇 SO 帖子中,许多答案表明 struct 赋值或多或少相当于memcpy,并且某些编译器甚至生成memcpy对赋值语句的调用。然而,memcpy当内存位置重叠时, 就没有被定义,这就引出了一个问题:它是为赋值而定义的吗?

这似乎符合预期,但我想知道 C 标准是否对此有任何规定。是否需要添加一个简单的检查

if (p1 != p2) *p1 = *p2;
Run Code Online (Sandbox Code Playgroud)

或使用memmove


仅供参考,这是我在 C 中实现自己的插槽映射(如此处所述)时出现的。容器中删除元素时,数组末尾的元素将被复制到删除的位置以保持所有内容连续。在被删除的元素位于数组末尾的情况下,它将被复制到自身(不是非常重要,因为该元素被认为是被删除的,但无论如何让我很好奇)。

Kei*_*son 5

任务定义明确。相应的调用memcpy不会是。

以下是标准中关于简单赋值N1570 6.15.6.1 第 3) 段的规定:

如果存储在一个对象中的值是从与第一个对象的存储以任何方式重叠的另一个对象读取的,则重叠应是精确的,并且两个对象应具有兼容类型的合格或不合格版本;否则,行为是未定义的。

而对于memcpy(7.24.2.1 第 2 段):

如果复制发生在重叠的对象之间,则行为未定义。

因此,memcpy尽管“或多或少”限定是适当的,但结构赋值等同于 是不正确的。一方面,正如我们在这里看到的,memcpy完全重叠的对象之间是未定义的,而赋值是明确定义的。另一方面,memcpy保留任何填充字节的值(成员之间或最后一个成员之后的间隙),而赋值时不保证这样做。可以通过复制每个成员而不是复制整个结构来实现分配。

话虽如此,实现可以memcpy以完全相同的方式实现分配。事实上,某些情况具有未定义的行为,这意味着实现可以自由地执行任何方便的操作。