当前位置: 首页 > 知识库问答 >
问题:

C 编译器优化具有指针复制的循环

充鑫鹏
2023-03-14

我在godbolt上编译这段代码。orgwith-O2和编译器不会使用一些memcpy对其进行优化,而是诚实地运行循环。

void foo(int* dst, int* src, int n)
{
    for (int i = 0; i < n; ++i)
    {
        dst[i] = src[i];
    }
}

但是,如果我将“= src[i]”替换为“= 0”,他们会使用memset。但同样,当我用“ = 1”替换它时,它们会运行一个循环。当要设置的值不为零时,为什么它们会避免使用 memcpy 和 memset?我认为这是他们将执行的第一批优化之一。

共有2个答案

轩辕煜
2023-03-14

来完成@MilesBudnek的好答案:

< code>memset以字节粒度工作,而您使用的< code>int通常大于1个字节(4个字节)。这就是为什么编译器不容易用内存集替换赋值< code>= 1的原因。

另请注意,-O2不能为GCC启用矢量化,尽管它显然可以为Clang启用矢量化。-ftree-vectorize(包含在-O3中)是GCC生成更快的SIMD指令所必需的(在许多平台上不如memcpy/memmobile/memset快)。

黄浩涆
2023-03-14

srcdest指向的范围可能重叠,在这种情况下, 的行为将未定义。因此,将此函数优化为只调用 memcpy是不合适的。

memmove是合适的,但当src ranges重叠时,它的行为与函数不同。考虑以下内容:

int arr[5] = {1, 2, 3, 4, 5};
foo(arr + 1, arr, 4);

您的函数将在调用后产生包含< code>{1,1,1,1,1}的< code>arr,而< code>memmove被指定为产生包含< code>{1,1,2,3,4}的< code>arr。因此,编译器也不能将< code>foo优化为对< code>memmove的调用。

C在C99中添加了< code>restrict关键字,告诉编译器两个范围不会重叠,但是C并没有采用这个特性。

 类似资料:
  • 在 C 或 C 中,如果编译器遇到一个 循环,其中计数器从 计数到 n, n 是一个变量(不是函数调用,也不是常量),编译器是否会通过检查变量 (绑定变量)是否会在循环期间更改(访问写入, 例如: 可以是循环前计算的字符串的长度),通过优化这里,我的意思是将其值复制到寄存器以避免内存访问? 下面是一个示例: 编译器会注意到这一点并对其进行优化吗?

  • 本文向大家介绍C/C++ 编译器优化介绍,包括了C/C++ 编译器优化介绍的使用技巧和注意事项,需要的朋友参考一下 0. gcc -o gcc -o 的优化仍然是机械的,想当然的。只有做到深入理解计算机系统,加深对编程语言的理解,才能写出最优化的代码。 Linux下gcc 优化级别的介绍  · gcc -o0 ⇒ 不提供任何优化;  · gcc -o1 ⇒ 最基本的优化,主要对代码的分支、表达式、

  • 我有一些遗留代码,其中包含一个浪费时间的循环,以便有时间完成eeprom读取(不好的做法): 但是,当为了提高速度而打开编译器优化时,会发生一些奇怪的事情。它不一定与该语句相关联,但我想知道编译器是否可能只是优化了时间延迟

  • 考虑下面的代码片段 通过-O3优化,最新的gcc和clang版本没有优化指向包装器的指针、指向底层函数的指针。参见第22行的组装: 在后面的+中,编译器将指针放置到,而不只是。 编辑2。同样模式的更简单的例子: gcc 8.2通过抛出指向包装器的指针并将直接存储在其位置(https://gcc.godbolt.org/z/nmibeo)成功地优化了这段代码。然而,按照注释更改代码行(即手动执行相同

  • 本文向大家介绍C#中尾递归的使用、优化及编译器优化,包括了C#中尾递归的使用、优化及编译器优化的使用技巧和注意事项,需要的朋友参考一下 递归运用 一个函数直接或间接的调用自身,这个函数即可叫做递归函数。 递归主要功能是把问题转换成较小规模的子问题,以子问题的解去逐渐逼近最终结果。 递归最重要的是边界条件,这个边界是整个递归的终止条件。 上面是个经典阶乘函数的实现。这里分2步: 1.转换,把10的阶

  • 我想开始在c#中开发,但是我使用Linux和VSCode进行开发,由于一些错误,我找不到答案,VSCode不运行代码,所以我决定借助这个链接(在linux终端上运行C#代码)来制作一个bash脚本来完成这部分代码: 到目前为止,我是这样做的: 它确实可以工作,但是我想让2美元(第二个参数)自动以1美元(第一个参数)命名,因此我不需要写2美元的值,只需写1美元创建一个同名的exe并用mono运行该e