c语言函数参数太多对性能是否有影响?

64位Linux汇编参数传递优化
本文探讨了64位Linux环境下汇编语言中函数参数传递的方式及其对性能的影响。通过实验对比了直接传递参数与使用结构体传递的不同情况下的性能损耗,发现合理利用结构体能有效减少参数压栈带来的开销。
64位汇编(linux)
当参数少于7个时, 参数从左到右放入寄存器: rdi, rsi, rdx, rcx, r8, r9。
当参数为7个以上时, 前 6 个与前面一样, 但后面的依次从 “右向左” 放入栈中,即和32位汇编一样。
参数个数大于 7 个的时候
H(a, b, c, d, e, f, g, h);
a->%rdi, b->%rsi, c->%rdx, d->%rcx, e->%r8, f->%r9
h->8(%esp)
g->(%esp)
call H


一般考虑用结构体来打包逻辑上相关的变量,传递给函数从而减少参数个数,那么这种方式对性能提升有帮助嘛?写了一个测试函数用来分析:

#include<stdio.h>
#include<stdlib.h>
#include<time.h>

typedef struct fun_p{
  char c;
  int  a;
  int  b;
  int  d;
  long f;
}_funp;


int func(int aa, int bb, int cc, int dd, char c, int a, int b, int d, double f)
{
  int ret = 0;
  if(c > 10)
	  ret = c*c + a + b + d + f * 2;
  else
	  ret = a + b + d + f * 2;
  return ret + aa + bb + cc + dd;
}

int funcs(int aa, int bb, int cc, int dd, _funp * inp)
{
  int ret = 0;
  char c = inp->c;
  int  a = inp->a;
  int  b = inp->b;
  int  d = inp->d;
  double f = inp->f;
  if(c > 10)
      ret = c*c + a + b + d + f * 2;
  else
      ret = a + b + d + f * 2;
  return ret + aa + bb + cc + dd;
}

int funcs2(int aa, int bb, int cc, int dd, _funp * inp)
{
  int ret = 0;
  char c = inp->c;
  if(c > 10)
      ret = c*c    + inp->a + inp->b + inp->d + inp->f * 2;
  else
      ret = inp->a + inp->b + inp->d + inp->f * 2;
  return ret + aa + bb + cc + dd;
}


int main(void)
{
  struct timespec time_start = {0, 0}, time_end = {0, 0};
  int aa = 9;
  int bb = 12;
  int cc = 39;
  int dd = 90;
  char c = 20;
  int a = 98;
  int b = 199;
  int d = 23;
  double f = 34.2;
  struct fun_p funp;
  int i, j;
  int run_num = 1000;
  long long total = 0;
  funp.c = c;
  funp.a = a;
  funp.b = b;
  funp.d = d;
  funp.f = f;

  clock_gettime(CLOCK_REALTIME, &time_start);
  for (i = 0; i < run_num; i++)
    for (j = 0; j < run_num; j++){
      c = c + 1;
      total += func(aa, bb, cc, dd, c, a, b, d, f);
    }
  clock_gettime(CLOCK_REALTIME, &time_end);
  printf("func   duration:%llus %lluns. total = %lld\n", time_end.tv_sec-time_start.tv_sec, time_end.tv_nsec-time_start.tv_nsec, total);


  total = 0;
  c = 20;
  clock_gettime(CLOCK_REALTIME, &time_start);
  for (i = 0; i < run_num; i++)
    for (j = 0; j < run_num; j++){
      funp.c = funp.c + 1;
      total += funcs(aa, bb, cc, dd, &funp);
    }
  clock_gettime(CLOCK_REALTIME, &time_end);
  printf("funcs  duration:%llus %lluns. total = %lld\n", time_end.tv_sec-time_start.tv_sec, time_end.tv_nsec-time_start.tv_nsec, total);

  total = 0;
  funp.c = 20;
  clock_gettime(CLOCK_REALTIME, &time_start);
  for (i = 0; i < run_num; i++)
    for (j = 0; j < run_num; j++){
      funp.c = funp.c + 1;
      total += funcs2(aa, bb, cc, dd, &funp);
    }
  clock_gettime(CLOCK_REALTIME, &time_end);
  printf("funcs2 duration:%llus %lluns. total = %lld\n", time_end.tv_sec-time_start.tv_sec, time_end.tv_nsec-time_start.tv_nsec, total);
  return 1;
}

编译命令: gcc -O3 test_func_parameter.c -o test_func_parameter -lrt

测试结果表明:
func duration:0s 1633997ns. total = 3235271710
funcs duration:0s 1524616ns. total = 3235271710
funcs2 duration:0s 1023802ns. total = 3235271710

结论

1、func相比funcs消耗的时间差不多,说明如果在函数内部用临时变量来转存一遍结构体变量的话,则函数参数多少对性能影响不大。
2、funcs2比funcs少了参数拷贝到函数变量的过程,但是却可以节省很多时间。说明将部分参数用结构体一次传输,并且函数内部通过结构体访问的话,可以节省时间,因为减少了函数参数过多导致的内存写入操作(参数压栈)。

3、如果函数本身计算量比较大,那可能参数的传输方式对性能影响就比较小了。



### C语言函数参数过多的风险 当C语言中的函数拥有过多的参数时,会带来一系列风险和负面影响: #### 1. 可读性和可维护性的降低 随着参数数量的增长,理解和记忆每个参数的意义变得困难。这不仅增加了开发人员的学习成本,也使得后续代码维护更加复杂。对于新加入项目的成员来说,掌握具有大量参数函数接口需要更多时间[^1]。 #### 2. 调用错误的可能性增大 更多的参数意味着更高的几率发生调用失误,比如传入不正确的参数顺序或类型。即使编译器能够捕捉某些类型的错误,在运行时仍可能存在难以发现的问题,特别是涉及到指针操作时更为明显[^3]。 #### 3. 对性能影响 尽管直接传递少量简单类型的参数不会显著影响执行效率,但如果涉及复杂的结构体或其他大型对象,则可能因为频繁复制而导致额外开销。此外,过多的参数也可能间接导致栈空间消耗过大,尤其是在嵌套调用场景下[^5]。 ```c // 不推荐的做法:太多参数使函数不易于管理和调试 void complexFunction(int a, int b, char c[], float d, double e, struct MyStruct f); // 推荐做法之一:通过结构体封装相关联的数据项来减少参数数目 struct DataBundle { int value; char stringData[MAX_LENGTH]; float floatValue; }; void simplerFunction(struct DataBundle bundle); ``` 为了提高代码质量和易用性,建议遵循以下原则: - 尽量保持函数简洁明了; - 如果确实存在多个关联紧密的信息需一起传递给某个函数处理,考虑创建一个新的复合数据类型(如结构体)来进行打包传输; - 利用全局变量或静态局部变量代替部分输入输出需求,但这通常不是最佳实践,除非有特殊理由支持这样做。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ITRonnie

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值