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

C中内联函数中的循环展开

庄萧迟
2023-03-14

我有一个关于C编译器优化以及内联函数中的循环何时/如何展开的问题。

我正在开发一个数字代码,它可以完成下面的示例。基本上,my_for()将计算某种模具,并调用op()<-code>对每个 my_type*argmy_func() 包装my_for()<-code>,创建参数并将函数指针发送到 …谁的工作是为每个( th double-

typedef struct my_type {
  int const n;
  double *dest[16];
  double const *src[16];
} my_type;

static inline void my_for( void (*op)(my_type *,int), my_type *arg, int N ) {
  int i;

  for( i=0; i<N; ++i )
    op( arg, i );
}

static inline void my_op( my_type *arg, int i ) {
  int j;
  int const n = arg->n;

  for( j=0; j<n; ++j )
    arg->dest[j][i] += arg->src[j][i];
}

void my_func( double *dest0, double *dest1, double const *src0, double const *src1, int N ) {
  my_type Arg = {
    .n = 2,
    .dest = { dest0, dest1 },
    .src = { src0, src1 }
  };

  my_for( &my_op, &Arg, N );
}

这工作正常。这些函数是内联的,代码(几乎)与在单个函数中内联编写所有内容并展开 j 循环一样高效,无需任何类型的my_type Arg

这里的混乱:如果我设置int const n=2;而不是int const n=arg-

在我的数字代码中,这相当于大约15%的性能命中率。如果重要的话,这里的n=4和这些j循环出现在 中的两个条件分支中。

我正在用icc(国际商会)12.1.5 20120612编译。我尝试了< code>#pragma unroll。以下是我的编译器选项(我错过了什么好的吗?):

-O3 -IPO -静态 -展开-激进 -FP-模型精确 -FP-模型源 -openmp -std=gnu99 -Wall -Wextra -Wno-未使用 -Winline -pedantic

谢谢


共有2个答案

邹杰
2023-03-14

它更快,因为您的程序不会为变量分配内存。

如果不必对未知值执行任何操作,则会将它们视为带有类型检查的#define常量2。它们只是在编译时添加的。

请您从两个标记中选择一个(我的意思是C或C),这很令人困惑,因为语言对const值的处理方式不同-C将它们视为普通变量,其值不能更改,在C语言中,它们有或没有根据上下文分配内存(如果您需要它们的地址,或者如果您需要在程序运行时计算它们,则分配内存)。

来源:“用C语言思考”。没有确切的引用。

徐学潞
2023-03-14

很明显,编译器不够“聪明”,无法传播n常量并展开for循环。事实上,它很安全,因为<code>arg-

为了在编译器生成过程中保持一致的性能,并最大限度地压缩代码,请手动展开。

像我这样的人在这种情况下(性能为王)所做的就是依赖宏。

宏将在调试构建中“内联”(有用),并且可以使用宏参数进行模板化(到某一点)。作为编译时常量的宏参数保证保持这种方式。

 类似资料:
  • 函数是一个可以重复使用的代码块,CPU 会一条一条地挨着执行其中的代码。CPU 在执行主调函数代码时如果遇到了被调函数,主调函数就会暂停,CPU 转而执行被调函数的代码;被调函数执行完毕后再返回到主调函数,主调函数根据刚才的状态继续往下执行。 一个 C/ C++ 程序的执行过程可以认为是多个函数之间的相互调用过程,它们形成了一个或简单或复杂的调用链条,这个链条的起点是 main(),终点也是 ma

  • C++ 类 & 对象 C++ 内联函数是通常与类一起使用。如果一个函数是内联的,那么在编译时,编译器会把该函数的代码副本放置在每个调用该函数的地方。 对内联函数进行任何修改,都需要重新编译函数的所有客户端,因为编译器需要重新更换一次所有的代码,否则将会继续使用旧的函数。 如果想把一个函数定义为内联函数,则需要在函数名前面放置关键字 inline,在调用函数之前需要对函数进行定义。如果已定义的函数多

  • 例如,我在golang中进行了以下测试: 如果我尝试构建它,我会收到以下内容: 有没有办法让编译器内联?如果是,是否有任何方法可以内联映射迭代?

  • 问题内容: 我有以下代码返回而不是循环内的每个值。 我需要怎么做才能获得循环值? 问题答案: 用 IIFE 封闭 **** 这样的话,价值将被保留,该次迭代的而不是将其设置为时间的最后一个值被称为回

  • 本文向大家介绍C和C ++中的循环,包括了C和C ++中的循环的使用技巧和注意事项,需要的朋友参考一下 在本教程中,我们将讨论一个程序,以了解C和C ++中的循环。 当我们不得不一次又一次地执行给定的块代码时,使用编程中的循环。它采用了一次又一次编写同一代码行的方法,并促进了DRY代码实践。 示例 对于循环 输出结果 While循环 输出结果

  • 我在一个循环中调用了一个异步函数来发送电子邮件,但是有一段时间控件没有返回,也没有发送电子邮件,但是主UI线程完成了。 当我把等待任务。WhenAll(发送电子邮件任务);循环内的线工作正常,但当我把这条线放在循环外时,它不工作,但实际上它应该在循环外。我在sendEmail方法中有很多异步方法,所以我认为有些线程彼此重叠。任何线索。