memcpy 与 C 中的赋值——应该是 memmove?

发布于 2024-10-26 09:43:21 字数 715 浏览 1 评论 0原文

正如 这个问题的答案中指出的,编译器(在本例中为 gcc- 4.1.2,是的,它很旧,不,我无法更改它)可以在它认为合适的地方用 memcpy 替换结构赋值。

我正在 valgrind 下运行一些代码,并收到有关 memcpy 源/目标重叠的警告。当我查看代码时,我看到了这一点(释义):

struct outer
{
    struct inner i;
    // lots of other stuff
};

struct inner
{
    int x;
    // lots of other stuff
};

void frob(struct inner* i, struct outer* o)
{
    o->i = *i;
}

int main()
{
    struct outer o;

    // assign a bunch of fields in o->i...

    frob(&o.i, o);
    return 0;
}

如果 gcc 决定用 memcpy 替换该赋值,那么它是无效调用,因为源和目标重叠。

显然,如果我将 frob 中的赋值语句更改为调用 memmove ,那么问题就会消失。

但这是编译器错误,还是该赋值语句在某种程度上无效?

As pointed out in an answer to this question, the compiler (in this case gcc-4.1.2, yes it's old, no I can't change it) can replace struct assignments with memcpy where it thinks it is appropriate.

I'm running some code under valgrind and got a warning about memcpy source/destination overlap. When I look at the code, I see this (paraphrasing):

struct outer
{
    struct inner i;
    // lots of other stuff
};

struct inner
{
    int x;
    // lots of other stuff
};

void frob(struct inner* i, struct outer* o)
{
    o->i = *i;
}

int main()
{
    struct outer o;

    // assign a bunch of fields in o->i...

    frob(&o.i, o);
    return 0;
}

If gcc decides to replace that assignment with memcpy, then it's an invalid call because the source and dest overlap.

Obviously, if I change the assignment statement in frob to call memmove instead, then the problem goes away.

But is this a compiler bug, or is that assignment statement somehow invalid?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

葬﹪忆之殇 2024-11-02 09:43:21

我认为你混淆了级别。只要能够保证正确的行为,gcc 通过调用其喜欢的任何库函数来替换赋值操作是完全正确的。

它不是“调用”memcpy 或标准意义上的任何内容。它只是使用其库中的一个函数,该函数可能具有保证正确性的附加信息。标准中描述的memcpy 属性被视为程序员的接口,而不是编译器/环境实现者的接口。

所讨论的实现中的memcpy是否实现了使其对赋值操作有效的行为是另一个问题。检查这一点甚至检查代码应该不那么困难。

I think that you are mixing up the levels. gcc is perfectly correct to replace an assignment operation by a call to any library function of its liking, as long as it can guarantee the correct behavior.

It is not "calling" memcpy or whatsoever in the sense of the standard. It is just using one function it its library for which it might have additional information that guarantees correctness. The properties of memcpy as they are described in the standard are properties seen as interfaces for the programmer, not for the compiler/environment implementor.

Whether or not memcpy in that implementation in question implements a behavior that makes it valid for the assignment operation is another question. It should not be so difficult to check that or even to inspect the code.

嘿嘿嘿 2024-11-02 09:43:21

据我所知,这是一个编译器错误。根据别名规则,允许 i&oi 进行别名,因为类型匹配并且编译器无法证明 oi 的地址可以以前没有被采取过。当然,使用重叠(或相同)指针调用 memcpy 会调用 UB。

顺便请注意,在您的示例中,o->i 是无意义的。我认为你的意思是oi...

As far as I can tell, this is a compiler bug. i is allowed to alias &o.i according to the aliasing rules, since the types match and the compiler cannot prove that the address of o.i could not have been previously taken. And of course calling memcpy with overlapping (or same) pointers invokes UB.

By the way note that, in your example, o->i is nonsense. You meant o.i I think...

一直在等你来 2024-11-02 09:43:21

我认为有一个拼写错误:“&o”而不是“0”。
在这个假设下,“重叠”实际上是严格的覆盖:memcpy(&o->i,&o->i,sizeof(o->i))。在这种特殊情况下,memcpy 行为正确。

I suppose that there is a typo: "&o" instead of "0".
Under this hypothesis, the "overlap" is actually a strict overwrite: memcpy(&o->i,&o->i,sizeof(o->i)). In this particular case memcpy behaves correctly.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文