c99中与类型无关的memcpy


Do any compilers transfer effective type through memcpy/memmove相关但有些不同

在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,即使所有三种类型具有相同的表示形式,它也不能与“unsigned”和“unsigned long”的类型相同.因此,编译器可以使用将该存储作为uint32_t以外的类型读取的代码执行任何喜欢的操作,即使该类型具有相同的表示形式.

在C99或C11中,有没有办法以允许编译器生成有效代码的方式执行复制,但会迫使编译器将目标视为包含没有有效类型的位模式[因此可以使用任何类型访问]?

最佳答案 如果你只是为函数使用返回类型,你可以摆脱所有有效的类型问题.

uint32_t increment_32_bit_uint (const void* p)
{
  u32_t result;
  memcpy(&result, p, sizeof(result));
  result++;
  return result;
}

这将迫使调用者小心他们的类型.当然,理论上这是某种不可变对象,而不是变量的就地变化.但是在实践中,如果你使用它,我认为无论如何你都会从中获得最有效的代码

x = increment_32_bit_uint(&x);

通常,我没有看到任何严格的别名优化如何在实际应用程序中有用,如果它们不将stdint.h类型视为与它们的原始数据类型等价的兼容类型.特别是,它必须将uint8_t视为字符类型,否则所有专业的低级C代码都会中断.

你的情况也一样.如果编译器知道unsigned int是32位,为什么它会决定为uint32_t的用户引起别名问题,反之亦然?这就是你如何使编译器变得无用.

点赞