[英]memcpy a void pointer to a union
码:
union foo
{
char c;
int i;
};
void func(void * src)
{
union foo dest;
memcpy(&dest, src, sizeof(union foo)); //here
}
如果我这样调用func()
:
int main()
{
char c;
int i;
func(&c);
func(&i);
return 0;
}
在呼叫func(&c)
,大小c
小于sizeof(union foo)
,这可能是危险的,是吗?
memcpy
的行是否正确? 如果没有,如何解决它?
我想要的是对memcpy
的安全调用,它将void *
指针复制到一个union
。
一点背景:这是从一个非常复杂的函数中提取的,包含void *
参数的func()
的签名是我无法控制的。 当然,该示例没有任何用处,因为我删除了所有与提供最少代码示例无关的代码。
在呼叫
func(&c)
,大小c
小于sizeof(union foo)
,这可能是危险的,是吗?
对,这将导致未定义的行为。 dest
可能包含来自c
周围的内存区域的一些字节,这些字节取决于编译器的内部工作方式。 当然,只要您只访问dest.c
,在大多数情况下不应该导致任何问题。
但让我更具体一点。 根据C标准,编写dest.c
但读取dest.i
将始终产生未定义的行为。 但是大多数平台上的大多数编译器也会对这些情况有一些明确定义的行为。 所以经常写dest.c
但是阅读dest.i
是有道理的,尽管标准说的是什么。 然而,在这种情况下,从dest.i
读取仍然会受到未知周围变量的影响,因此它不仅从标准的角度来看是不确定的,而且在非常实际的意义上也是如此。
您还应该考虑一种罕见的情况: c
可能位于已分配内存页的最末端。 (这是指从操作系统和最终内存管理单元(MMU)硬件分配的内存页,而不是由malloc
和朋友完成的逐块用户空间分配。)在这种情况下,读取多个单字节可能会导致访问未映射的内存,因此导致严重错误,很可能是程序崩溃。 鉴于你的c
作为main中的自动变量的位置,这似乎不太可能,但我认为这个代码片段只是一个例子。
memcpy
的行是否正确? 如果没有,如何解决它?
取决于你想做什么。 就目前而言,代码没有多大意义,所以我不知道你可能会想到什么样的正确合理的应用程序。 也许您应该将src
对象的sizeof
传递给func
。
memcpy的行是否正确? 如果没有,如何解决它?
你应该传递void指针指向的内存大小 ,这样你就可以知道src
有这么多的大小,所以你只需要复制这么多的数据......
为了更安全,你应该计算目的地的大小,并根据你应该通过大小,这样可以避免读写时的非法访问 。
memcpy
很好。 通过传递联盟中最小成员的地址,您将在较大的成员中以垃圾结束。 避免垃圾位的一种方法是默认情况下对func
所有调用 - 我假设你控制它 - 只使用指向较大成员的指针 - 这可以通过将较大的成员设置为较小的成员来实现: i = c
然后调用func(&i)
。
func
本身还可以。
问题在于调用者是否确实在调用func()
时引用的内存至少是sizeof(union foo)
。
如果后者总是如此,一切都很好。 在OP的例子中,两次调用func()
情况并非如此。
如果调用func()
时引用的内存小于sizeof(union foo)
则memcpy()
会引发未定义的行为。
既然你知道要复制什么和大小,为什么不给出一个更明确的函数,让函数知道如何复制无效指针指向的正确大小的内存。
union foo
{
char c;
int i;
};
void func(void * src, const char * type)
{
union foo dest;
if(strcmp(type, "char") == 0){
memcpy(&dest, src, 1);
}else if(...){
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.