memcpy 与 C 中的赋值——应该是 memmove?
正如 这个问题的答案中指出的,编译器(在本例中为 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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
我认为你混淆了级别。只要能够保证正确的行为,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 ofmemcpy
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.据我所知,这是一个编译器错误。根据别名规则,允许
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 ofo.i
could not have been previously taken. And of course callingmemcpy
with overlapping (or same) pointers invokes UB.By the way note that, in your example,
o->i
is nonsense. You meanto.i
I think...我认为有一个拼写错误:“&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.