C:Memcpy vs Shifting:效率更高?

时间:2012-02-06 13:31:42

标签: c performance casting benchmarking memcpy

我有一个包含16&的字节数组。 32位数据样本,并将它们转换为Int16和Int32我目前只做一个2(或4)字节的memcpy。

因为memcpy可能没有针对只有两个字节的长度进行优化,所以我想知道使用整数算术(或联合)将字节转换为Int32是否更有效。

我想知道调用memcpy与位移的效率是多少,因为代码在嵌入式平台上运行。

2 个答案:

答案 0 :(得分:3)

我会说memcpy不是这样做的方法。但是,找到最佳方式很大程度上取决于数据在内存中的存储方式。

首先,您不想获取目标变量的地址。如果它是局部变量,您将强制它到堆栈而不是让编译器选择将它放在处理器寄存器中。仅此一点可能非常昂贵。

最通用的解决方案是逐字节读取数据并对结果进行算术组合。例如:

uint16_t res = (  (((uint16_t)char_array[high]) << 8)
                | char_array[low]);

32位情况下的表达式有点复杂,因为您有更多选择。您可能想要检查最佳的汇编程序输出。

替补1:建立巴黎,并将它们合并:

uint16_t low16 = ... as example above ...;
uint16_t high16 = ... as example above ...;
uint32_t res = (  (((uint32_t)high16) << 16)
                | low16);

Alt 2:一次8位移位:

uint32_t res = char_array[i0];
res = (res << 8) | char_array[i1];
res = (res << 8) | char_array[i2];
res = (res << 8) | char_array[i3];

上面的所有示例都与所用处理器的字节顺序无关,因为索引值决定了要读取的部分。

如果1)设备的字节顺序(字节顺序)与字节存储在数组中的顺序相匹配,则可以使用下一种解决方案; 2)已知数组被放置在对齐的存储器地址上。后一种情况取决于机器,但是如果表示16位数组的字符数组在偶数地址上开始则是安全的,而在32位情况下,它应该从可分为4的地址开始。在这种情况下,你可以在一些指针技巧之后简单地读取地址:

uint16_t res = *(uint16_t *)&char_array[xxx];

其中xxx是与内存中第一个字节对应的数组索引。请注意,这可能与最低值的索引不同。

我强烈建议使用第一类解决方案,因为它是endianess-neutral。

无论如何,它们都比你的memcpy解决方案更快。

答案 1 :(得分:2)

memcpy对于“移位”无效(在同一数组中移动数据的偏移量小于其长度);试图使用它来调用非常危险的未定义行为。见http://lwn.net/Articles/414467/

您必须使用memmove或您自己的换档循环。对于大约64字节以上的大小,我希望memmove要快得多。对于极短暂的班次,你自己的循环可能会赢。请注意,memmove的开销高于memcpy,因为它必须确定哪个复制方向是安全的。你自己的循环已经知道(大概)哪个方向是安全的,所以它可以避免额外的运行时检查。