首页 > 解决方案 > 在 C 中复制两个相邻字节的最快方法是什么?

问题描述

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

memcpy(Ptr, (const char[]){'a', 'b'}, 2);

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

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

Ptr[0] = 'a';
Ptr[1] = 'b';

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

*(uint16_t*)Ptr = *(uint16_t*)(unsigned char[]){'a', 'b'};

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

问候,
Hank Sauri

标签: cperformancememory

解决方案


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

memcpy(Ptr, (const char[]){'a', 'b'}, 2);

Ptr[0] = 'a';
Ptr[1] = 'b';

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

mov     eax, 25185
mov     WORD PTR [something], ax

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

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


你建议的第三个

*(uint16_t*)Ptr = *(uint16_t*)(unsigned char[]){'a', 'b'};

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

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


推荐阅读