假设memcpy固定大小被优化是否安全?

时间:2015-03-22 06:45:31

标签: c optimization

使用GCC你可以做这样的事情。

void foo(MyStruct *a, const MyStruct *b)
{
    memcpy(&a[0], b, sizeof(*a));
    memcpy(&a[1], b, sizeof(*a));
    memcpy(&a[2], b, sizeof(*a));
}

在编写可移植代码时,使用现代C编译器*,这可以优化输出相同的asm ...

void foo(MyStruct a[3], const MyStruct *b)
{
    a[0] = *b;
    a[1] = *b;
    a[2] = *b;
}

我的问题是,假设对memcpy的函数调用将总是进行优化是否合理?

我之所以这样问是因为我正在考虑在一个宏中使用memcpy,这个宏在编译时已知多次实例化。如果这会在某些平台上调用memcpy,我宁愿完全避免调用它。 例如:Implement generic swap macro in C


* 现代C编译器(GCC / Clang / MSVC / ICC)。标准/安全优化级别设置。

2 个答案:

答案 0 :(得分:3)

一些天真的C编译器(如tinycc)不会进行太多优化,也不会优化对memcpy的调用;但它们生成的代码很慢,没有人关心二进制代码性能会使用它们。

然而,使用tcc的一个很好的理由可能是当你完全不关心运行时性能时,但你很关心 tiny 编译器能否快速编译

理论上,optimizationC99标准并未规定C11(即使是真正的或虚拟的计算机也不是必需的:您可以使用一堆标准C程序运行人类的奴隶,但这是不道德的,不可靠的,低效的)。并且C99标准不要求编译器;它可能是一个天真的解释器,仍然是一个标准的符合实现。

实际上,任何严肃的C编译器在被要求优化时都会优化您对memcpy的调用

另见this answer on Programmers

所以我会像你一样使用memcpy,但要记录一个现代的C 优化编译器(并且可能推荐最近的版本< / em>编译器至少GCC 4.8,或至少Clang 3.4

答案 1 :(得分:0)

memcpy函数是一个非常广泛的函数,它将void *个参数作为输入。

来自ISO / IEC 9899:1999(C99):

梗概:

  

void * memcpy(void * restrict s1,const void * restrict s2,size_t n);

说明

  

memcpy 功能将 s2 指向的对象中的n个字符复制到 s1 指向的对象中。如果在重叠的对象之间进行复制,则行为未定义。

正如您所看到的,对于允许对其进行哪些优化,描述非常模糊。但是,函数原型使用关键字restrict,允许优化编译器将两者识别为不同的内存区域。

但是再次来自§6.7.3.1限制的正式定义:

  

翻译人员可以自由地忽略使用限制的任何或所有别名含义。

建议可能并非所有优化编译器都直接识别该标志。在这种情况下,memcpy将(从编译器的角度)处理可能的重复/重叠内存区域,并且无法将a[0] = *b的功能等效性推断,因为这可能会修改b的值同样。

标准可能在C11中有所改变,但我没有副本,所以我不能说......

编辑:

N1570草案对于这两个部分都有相同的内容,所以它应该是相同的,尽管我没有阅读整个内容以确保这一点。