从未初始化的变量memcpy是未定义的行为吗?

是否使用未初始化的变量作为C中memcpy未定义行为的src

 void foo(int *to) { int from; memcpy(to, &from, sizeof(from)); } 

C委员会提出了对缺陷报告451的回应:未初始化的自动变量的不稳定性是:

问题3的答案是,当在不确定的值上使用时,库函数将表现出未定义的行为。

缺陷中的问题已经寻求对memcpy和fwrite的豁免,如果事实确实如此:

[…]一个人希望能够使用memcpy在没有未定义行为的情况下在结构中复制未初始化的填充字节这一事实是使用未初始化对象的值不是未定义的行为的原因。 这似乎表明具有未初始化填充字节的结构的fwrite不应该表现出未定义的行为。

建议响应的这一部分似乎是针对未初始化填充的问题:

该委员会还指出,结构内的填充字节可能是“摇摆”表示的一种不同forms。

我们可以看到表单缺陷报告338:C99似乎将不确定的值排除在未初始化的寄存器之外,这与过去的预期有些不同。 除其他外,它说:

[…]我认为将类型unsigned char排除在陷阱表示之外的意图是允许它用于复制(通过memcpy)任意内存,如果内存可能包含某些类型的陷阱表示。[.. ]

阅读不确定内容的博客文章也可能未定义,涵盖了在C井中阅读不确定值的演变,并使我对上面提到的变化有了更多的了解。

值得注意的是,这与C ++的不同之处在于, 从狭义的无符号字符中读取不确定的值不是未定义的行为 , 缺陷报告240注意到这种差异:

C委员会正在处理DR338中的类似问题。 根据这一分析,他们计划采用几乎与上述方法相反的方法,通过增加左值到左值转换版本的描述。 CWG没有考虑对无符号字符的访问如果在寄存器中分配并且需要从那个角度重新评估提议的分辨率,则可能仍会陷阱。 另见问题129。

这是与复制操作相关的已定义行为,除非int在您的系统中有陷阱表示。 当定义int from时,内存在堆栈上分配。 此int的内容是当时堆栈中该位置发生的任何内容。 因此,最终结果是,未定义复制到的int的值(不确定)。

其他答案引用了C标准的引用,当未初始化变量的值被“使用”时,会发生未定义的行为。 如果您不使用该值,这显然不适用。 在复制/分配未初始化的变量时,C11标准中还有另一个提到的未定义行为:

6.3.2.1p2

如果左值指定了一个自动存储持续时间的对象,该对象可以使用寄存器存储类声明(从未使用其地址),并且该对象未初始化(未使用初始化程序声明,并且在使用之前未对其进行任何赋值) ),行为未定义。

这也不会影响您的代码,因为当您调用memcpy时会使用from的地址

C11标准的另一个相关部分是6.2.6.1

某些对象表示不需要表示对象类型的值。 如果对象的存储值具有这样的表示,并且由不具有字符类型的左值表达式读取,则行为是未定义的。 如果这样的表示是由副作用产生的,该副作用通过不具有字符类型的左值表达式修改对象的全部或任何部分,则行为是未定义的。这种表示称为陷阱表示。

一些非常古老的处理器可以在软件可见的奇偶校验位中使用陷阱表示 ,或者在非二进制补码架构中使用“负零”。 例如,x86处理器没有int陷阱表示。

(早先 – 没有注意到的地址 通过 )。 不,这不会导致未定义的行为,只是from具有不确定的值。 如果您打算使用未初始化变量的值 ,程序将具有明确定义的行为。

(因为分配空间而不是初始化变量不是UB 。)