sup*_*cat 6 c strict-aliasing memcpy language-lawyer
根据N1570 6.5/6:
如果使用memcpy或memmove将值复制到没有声明类型的对象中,或者将其复制为字符类型数组,则该访问的修改对象的有效类型以及不修改该值的后续访问的有效类型是复制值的对象的有效类型(如果有).
这表明即使在"long"和其他整数类型具有相同表示的系统上,以下内容也会调用Undefined Behavior:
#if ~0UL == ~0U
#define long_equiv int
#elif ~0UL == ~0ULL
#define long_equiv long long
#else
#error Oops
#endif
long blah(void)
{
long l;
long_equiv l2;
long_equiv *p = malloc(sizeof (long));
l = 1234;
memcpy(p, &l, sizeof (long));
l2 = *p;
free(p); // Added to address complaint about leak
return l2;
}
Run Code Online (Sandbox Code Playgroud)
由于指向的数据l明显具有有效类型long且指向的对象p没有声明类型,因此memcpy应将存储的有效类型设置为long.由于不允许读取使用类型的左值long_equiv来读取具有有效类型的对象long,因此代码将调用未定义的行为.
鉴于在C99之前memcpy是将一种类型的数据复制到另一种类型的存储的标准方法之一,新规则memcpy导致许多现有代码调用未定义的行为.如果规则是使用memcpy写入分配的存储而离开目的地而没有任何有效类型,则将定义行为.
memcpy当用于将信息复制到分配的存储时,是否存在任何不表现为memcpy保留目的地的有效类型的编译器,或者为了数据转换的目的而应该将其视为"安全"?如果某些编译器确实将有效类型的源应用于目标,那么以类型无关的方式复制数据的正确方法是什么?"复制为字符类型数组"是什么意思?
C标准说有效类型被转移。因此,根据定义,所有符合标准的编译器都会传输有效类型。
您的代码示例通过违反严格的别名规则而导致未定义的行为,因为有效类型的值long是由类型 的左值读取的long long。
C89 中也是如此,我不确定您所说的“C99 中的新规则”是什么(除了long longC89 中没有的事实)。
确实,当 C 被标准化时,一些现有代码具有未定义的行为。人们确实继续编写具有未定义行为的代码。
“复制为字符类型数组”是什么意思?
这意味着使用字符类型逐个字符地复制。
以类型无关的方式复制数据的正确方法是什么?
据我所知,“删除有效类型”是不可能的。要使用 a 正确读取值long long *,您必须指向有效类型的位置long long。
在您的代码中,例如:
// If we have confirmed that long and long long have the same size and representation
long long x;
memcpy(&x, p, sizeof x);
return x;
Run Code Online (Sandbox Code Playgroud)
联合别名是另一种选择。
如果您不喜欢这一切,请使用-fno-strict-aliasing.
| 归档时间: |
|
| 查看次数: |
271 次 |
| 最近记录: |