使用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)。标准/安全优化级别设置。
答案 0 :(得分:3)
一些天真的C编译器(如tinycc)不会进行太多优化,也不会优化对memcpy
的调用;但它们生成的代码很慢,没有人关心二进制代码性能会使用它们。
然而,使用tcc
的一个很好的理由可能是当你完全不关心运行时性能时,但你很关心 tiny 编译器能否快速编译
理论上,optimization或C99标准并未规定C11(即使是真正的或虚拟的计算机也不是必需的:您可以使用一堆标准C程序运行人类的奴隶,但这是不道德的,不可靠的,低效的)。并且C99标准不要求编译器;它可能是一个天真的解释器,仍然是一个标准的符合实现。
实际上,任何严肃的C编译器在被要求优化时都会优化您对memcpy
的调用
所以我会像你一样使用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草案对于这两个部分都有相同的内容,所以它应该是相同的,尽管我没有阅读整个内容以确保这一点。