分配vs memcpy - 在这种情况下会更快

时间:2012-02-28 09:57:18

标签: c++ c optimization memcpy

两者中哪一个更快:?

1

char* _pos ..;
short value = ..;

*((short*)_pos = va;

2

char* _pos ..;
short value = ..;

memcpy(_pos, &value, sizeof(short));

7 个答案:

答案 0 :(得分:8)

与所有“哪个更快?”一样问题,你应该对它进行基准测试,以便亲眼看看。如果重要的话,那就问问为什么然后挑选你想要的东西。

在任何情况下,您的第一个示例在技术上是 未定义的行为 ,因为您违反了严格别名。因此,如果您必须选择没有基准测试,请选择第二个。


要回答实际问题,速度更快可能取决于pos的对齐方式。如果它正确对齐,那么1可能会更快。如果没有,则2可能会更快,具体取决于编译器如何优化它。 (如果硬件不支持错位访问,则1甚至可能崩溃。)

但这都是猜测工作。你确实需要对它进行基准测试才能确定 至少,您应该查看已编译的程序集:

:     *(short *)_pos = value;

mov WORD PTR [rcx], dx

VS

:     memcpy(_pos, &value, sizeof(short));

mov WORD PTR [rcx], dx

在这种情况下(在MSVC中)显示具有默认优化的完全相同的程序集。所以你可以期待性能相​​同。

答案 1 :(得分:4)

gcc的优化级别为-O1或更高,以下两个函数在x86上编译为完全相同的机器代码:

void foo(char *_pos, short value)
{
        memcpy(_pos, &value, sizeof(short));
}

void bar(char *_pos, short value)
{
        *(short *)_pos = value;
}

答案 2 :(得分:2)

编译器可以以相同的方式实现它们 如果它天真地做,分配会更快。

出于任何实际目的,它们都会立即完成,您无需担心。

另请注意,您可能存在对齐问题(_pos可能无法在2个字节上对齐,这可能会在某些处理器上崩溃),并输入惩罚问题(编译器可能会假设_pos指向未更改,因为您使用short *)编写。

答案 3 :(得分:0)

重要吗?可能是第一种情况会为您节省一些周期(取决于编译器的复杂程度和优化)。但值得注意的是可读性和可维护性吗?

由于过早优化而引入了许多错误。您应该首先确定瓶颈,如果这个任务是瓶颈 - 对每个选项进行基准测试(照顾其他人已经提到的对齐和其他问题)。

答案 4 :(得分:0)

问题是依赖于实现。在实践中,除了复制sizeof(短)字节之外什么都不做,如果一个人要慢一点,那就是memcpy。对于相当大的数据集,如果一个更快,它通常将是memcpy。

正如所指出的,#1调用未定义的行为。

我们可以看到,简单的赋值肯定更容易读写,并且比两者都更容易出错。清晰度和正确性应该首先出现,即使在性能关键领域也是如此,原因很简单,优化正确的代码比修复优化的错误代码更容易。如果这确实是一个C ++问题,那么需要这样的代码(将类型系统推平到x射线并围绕位进行推广的强制转换或memcpy)应该是非常非常罕见的。

答案 5 :(得分:0)

如果您确定不存在对齐问题,并且您确实发现这是一个瓶颈情况,请继续执行第一步。

如果您不熟悉调用memcpy,请执行以下操作:

*pos = static_cast<char>(value & 0xff );
*(pos+1) = static_cast<char>(value >> 8 );

虽然如果你打算这样做,那么使用无符号值。

上面的代码也确保你得到小端。 (如果你想要big-endian,显然可以改变作业的顺序)。如果数据作为某种二进制blob传递,你可能想要一致的字节序,我猜,这是你想要创建的。

如果要创建二进制blob,您可能希望使用Google协议缓冲区之类的内容。还有boost :: serialize,包括二进制序列化。

答案 6 :(得分:0)

您可以使用union来避免破坏别名规则并调用函数:

union {
    char*  c;
    short* s;
} _pos;

short value = ...

_pos->s = value;
相关问题