在C中高效地返回多个值

im9ewurl  于 2023-08-03  发布在  其他
关注(0)|答案(2)|浏览(103)

当C函数必须返回多个值时,有几种方法可以做到这一点。
现在我对其中两种方法的相对效率感兴趣:
a)将值绑定到struct foo中。填充一个本地foo,并返回它。
B)传递要填充的指针。
(我正在处理一些混合了这两种代码的遗留代码。
就这篇文章而言:

  • 所有返回的值都是基元。int、指针值等。所以sizeof(foo)非常小。
  • 让struct foo不透明不是问题。
  • 这些函数最多有12个参数,包括所有ptr-to-return-value参数。
  • 假设一个有点现代的编译器,例如GCC 11或更高版本。

显然,内联会使这个问题变得毫无意义。
不同的方法会影响编译器内联的能力吗?
如果不内联,这两种方法之间是否会有性能差异?
在函数参数中放置返回值指针参数会有影响吗?是取决于编译器的内联能力,还是取决于非内联性能?
为清楚起见,编辑了(a)。

2hh7jdfx

2hh7jdfx1#

这是ABI特有的。

Linux / x86-64上,一个struct只有两个单词(例如两个指针或两个intptr_t或两个long-s)在两个寄存器中返回。这比例如要快得多。malloc-ing它,并且可能比由调用者在调用堆栈上分配的写入两个字struct更快(那么它可能在一些快速CPU cache;请记住,在最近的处理器上,高速缓存未命中可能需要数百纳秒,或者一百个寄存器寄存整数加法机器指令所需的时间)
但是内联函数并不总是更快。您还可以使用部分求值技术或C代码生成(如RefPerSys
使用最新的GCC编译器,还可以考虑编译所有C或C
文件 *,并使用链接时优化(例如:-flto -O2

owfi6suc

owfi6suc2#

我想,问题是:更快(假设没有内联):

void fn(int *a, int *b, int *c) {
  *a = ...;
  *b = ...;
  ... etc.
}

字符串

void fn(struct foo *f) {
  f->a = ...;
  f->b = ...;
  ... etc.
}

  • 在隔离 *,struct变体将更快,因为它不必从内存中加载单个指针(在x86上,您只能在寄存器中传递几个指针,其余的将溢出到堆栈中)。

但是,调用方上下文也很重要。如果调用者看起来像这样:

int a; double d1; int b; double d2; int c; ...
struct foo f;
fn(&f);
a = f->a;
b = f->b;
... etc.


则节省的部分将被“解包foo”代码大大抵消。
但如果呼叫者看起来像这样:

struct foo f;
fn(&f);
if (f->a != 0) ...
int x = f->a + f->b;
... etc.


则“解包”代码将不存在。

相关问题