在 C 中复制两个相邻字节的最快方法是什么?

2 c memory performance

好的,让我们从最明显的解决方案开始:

memcpy(Ptr, (const char[]){'a', 'b'}, 2);
Run Code Online (Sandbox Code Playgroud)

调用库函数的开销很大。编译器有时不优化它,我不会依赖编译器优化,但即使 GCC 很聪明,如果我将程序移植到带有垃圾编译器的更奇特的平台上,我不想依赖它。

所以现在有一个更直接的方法:

Ptr[0] = 'a';
Ptr[1] = 'b';
Run Code Online (Sandbox Code Playgroud)

它不涉及任何库函数的开销,而是进行两个不同的分配。第三,我们有一个双关语:

*(uint16_t*)Ptr = *(uint16_t*)(unsigned char[]){'a', 'b'};
Run Code Online (Sandbox Code Playgroud)

如果遇到瓶颈,我应该使用哪一种?在 C 中只复制两个字节的最快方法是什么?

问候,
汉克·萨里

Ant*_*ala 5

您建议的方法中只有两种是正确的:

memcpy(Ptr, (const char[]){'a', 'b'}, 2);
Run Code Online (Sandbox Code Playgroud)

Ptr[0] = 'a';
Ptr[1] = 'b';
Run Code Online (Sandbox Code Playgroud)

在 X86 GCC 10.2 上,两者都编译为相同的代码

mov     eax, 25185
mov     WORD PTR [something], ax
Run Code Online (Sandbox Code Playgroud)

由于as-if 规则,这是可能的。

由于好的编译器可以确定这些是相同的,因此请使用更容易在您的 cse 中编写的编译器。如果您要设置一两个字节,请使用后者,如果有几个使用前者或使用字符串而不是复合文字数组。


你推荐的第三个

*(uint16_t*)Ptr = *(uint16_t*)(unsigned char[]){'a', 'b'};
Run Code Online (Sandbox Code Playgroud)

在使用 x86-64 GCC 10.2 时编译为相同的代码,即在这种情况下它的行为相同。

但此外它还有2-4 个未定义行为点,因为它有两次严格的别名违规和两次,再加上可能在源和目标上未对齐的内存访问。未定义的行为并不意味着它不能像您预期的那样工作,但也不意味着它必须按您的预期工作。行为未定义。它可能无法在任何处理器上工作,包括 x86。为什么你会如此关心一个糟糕的编译器的性能,以至于你会编写无法在一个好的编译器上运行的代码?!