目录
C 语言 是一门面向过程的编程语言,通过一个又一个函数,把计算、过程控制等逻辑,包装成一个个独立的处理单元。
C 语言
既然是函数调用,就一定会有参数和返回值的传递问题,因此也就产生了多种不同的编程范式,比如:
这篇文章就来轻松一下,聊一聊这些函数调用范式在开发过程中的一些小思考。
我们假设有一个算法函数,输入两个整型参数,输出一个整型结果,并且输出一个错误代码。
既然所有的信息都是通过参数来传递的,那么函数定义就应该是下面这样:
void func1(int a, int b, int *result, int *err_code) int c = a + b; *result = c; err_code = 0; // 沿用 Linux 中的习惯,0 表示没有发生错误。
因为不需要返回任何数据,因此函数签名的返回类型就是 void 。
因为调用者需要获取输出结果和错误码,因此在形参中, result 和 err_code 需要传递指针类型的变量。
result
err_code
面对这样的函数签名,调用者就必须显示的定义两个变量 result 和 err_code ,用来接收函数的输出。
// 调用者代码 int result, err_code; func(1, 2, &result, &err_code); if (0 == err_code) printf("Success. result = %d \n", result); printf("Failed. err_code = %d \n", err_code);
这种函数范式的优点就是:在调用形式上统一,无论参数类型是什么(基础类型、结构体等待),都是整齐划一的函数调用写法。
缺点就是有点累赘。
面对任何一个函数,调用者都必须定义一个 err_code 变量传递进去。
如果一个函数是过程控制类型的,压根就不会产生什么错误码,这样的函数调用就显得很臃肿,因为调用者压根就不需要检查错误码。
也就是把第一种方式中的 err_code 参数,通过函数返回值赋值给调用者。
这种函数编程范式还是比较常见的,返回值只表示错误码,其他的输出结果都通过参数引用(指针)来传递。
int func2(int a, int b, int *result) int c = a + b; *result = c; return 0; // 返回错误码
这样的函数范式跟 POSIX 风格很像了。
POSIX
面对这样的函数,调用者的写法就会变成这样:
// 调用者代码 int result, err_code; err_code = func2(1, 2, &result); if (0 == err_code) printf("Success. result = %d \n", result); printf("Failed. err_code = %d \n", err_code);
看起来好像跟第一种方式没有什么本质区别,但是再看一下下面这样的写法呢:
// 调用者代码 int result; if (0 == func2(1, 2, &result)) printf("Success. result = %d \n", result); printf("Failed.\n");
这样的代码风格,在 Linux 中是不是很常见?当不需要处理错误码时,这样的编程方式会更方便一些。
Linux
也就是把第一种方式中的 result 参数,通过函数返回值赋值给调用者。
int func3(int a, int b, int *err_code) int c = a + b; err_code = 0; return c;
这有点类似 Unix 中的风格:
Unix
面对这样的函数签名,调用者的调用方式如下:
// 调用者代码 int result, err_code; result = func3(1, 2, &err_code))