编写符合严格别名的memcpy符合条件

Ole*_*eev 8 c c++ strict-aliasing memcpy

在询问"如何实现符合严格别名规则的memcpy函数"时,一般的答案就是这样的

void *memcpy(void *dest, const void *src, size_t n)
{
    for (size_t i = 0; i < n; i++)
        ((char*)dest)[i] = ((const char*)src)[i];
    return dest;
}
Run Code Online (Sandbox Code Playgroud)

但是,如果我理解正确的话,编译器可以自由地重新排序对memcpy的调用并访问dest,因为它可以使用任何其他指针类型的读取重新排序写入char*(严格的别名规则阻止仅对char*的读取进行重新排序)到任何其他指针类型).

这是正确的,如果是的话,有没有办法正确实现memcpy,还是我们应该依赖内置的memcpy?

请注意,这个问题不仅涉及memcpy,还涉及任何反序列化/解码功能.

dor*_*ron 6

严格别名规则明确地将强制char类型转换为类型(请参阅下面的最后一个要点),因此编译器将在您的情况下执行正确的操作.转换之类的东西时类型双关只是一个问题intshort.在这里,编译器可能会做出会导致未定义行为的假设.

C99§6.5/ 7:

对象的存储值只能由具有以下类型之一的左值表达式访问:

  • 与对象的有效类型兼容的类型,
  • 与对象的有效类型兼容的类型的限定版本,
  • 与对象的有效类型对应的有符号或无符号类型的类型,
  • 与有效类型的对象的限定版本对应的有符号或无符号类型的类型,
  • 聚合或联合类型,包括其成员中的上述类型之一(包括递归地,子聚合或包含联合的成员),或者
  • 一个字符类型.


Jam*_*nze 5

由于(char*)dest和 都(char const*)src指向char,编译器必须假设它们可能是别名。另外,有一条规则说指向字符类型的指针可以为任何东西起别名。

所有这些都与 无关memcpy,因为实际签名是:

void* memcpy( void* restrict dest, void* restrict src, size_t n );
Run Code Online (Sandbox Code Playgroud)

这告诉编译器不能有别名,因为用户保证它。您不能使用memcpy复制重叠区域而不会导致未定义的行为。

无论如何,给定的实现没有问题。

  • OP 关注的是编译器,根据所示的实现,将 **call** 重新排序到他们的 `memcpy` 实现,并具有对 `dest` 指向的区域的读取访问权限。 (4认同)
  • @PascalCuoq 这是我的第一段所涵盖的。 (2认同)