相关的,但是从有些不同,Do any compilers transfer effective type through memcpy/memmove类型无关的memcpy在C99
在C89,memcpy
和memmove
需要表现得好像源和目标正在使用的字符类型访问,复制的所有位源到目的地而不考虑被复制的数据的类型。
C99更改了语义,因此如果将具有有效类型的对象复制到没有声明类型的存储器(通常是从malloc或其他此类函数接收到的存储器),它将在目标存储器中创建一个只能访问的对象使用源类型。
例如,以下代码将在C89上具有完全定义的行为 “unsigned int”和“unsigned long”具有相同的32位表示但在C99下具有未定义行为的所有平台。
#include <stdio.h>
#include <string.h>
void increment_32_bit_uint(void *p)
{
uint32_t temp;
memcpy(&temp, p, sizeof temp);
temp++;
memcpy(p, &temp, sizeof temp);
}
int main(void)
{
unsigned *ip = malloc(sizeof (unsigned));
unsigned long *lp = malloc(sizeof (unsigned long));
*ip = 3; *lp = 6;
increment_32_bit_uint(ip);
increment_32_bit_uint(lp);
printf("%u %lu", *ip, *lp);
return 0;
}
根据C99的规则,通过分配存储到“increment_32_bit_uint”功能将使其设置有效的类型来uint32_t的,不能是同一类型的两个“签名”和“无符号长”,即使所有三个类型具有相同的表示形式。因此,即使该类型具有相同的表示形式,编译器也可以使用它读取该存储的代码来执行任何类似于uint32_t的类型的代码。
在C99或C11中,是否有任何方式执行副本,使得编译器能够生成高效的代码,但会强制编译器将目标视为包含一个没有有效的类型[因此可以使用任何类型访问]?
海合会包括''和'' –
xvan
@xvan后编译使用没有警告'-std = c99'或'-std = c11'您的例子:一个特定的编译器(或者甚至每一个编译器目前存在)恰巧做了一些事情并不意味着标准强制要求继续这样做。有几种情况几乎每个编译器都存在数十年没有标准要求它们这样做的相同行为,直到一些编译器作者认为他们不再需要支持这些情况,所以代码在当今所有编译器并不意味着它不会调用UB。 – supercat
@xvan:Per N1570:“如果使用memcpy或memmove将值复制到没有声明类型的对象中,或者将其复制为字符类型的数组,则该访问和后续访问的修改对象的有效类型不修改该值的值是从中复制该值的对象的有效类型,如果它有一个。“我没有看到说有效类型不会被设置为“uint32_t”,也没有任何其他类型的读取不会调用未定义行为。 – supercat