起因
最近,在回顾C语言知识的时候,突发奇想——C语言怎么实现可选参数呢?在一些面向对象语言中,我们在设置函数时使用函数的默认参数,帮助我们完成一些非必要参数的初始化。那么,在C语言中怎么实现这一方便的特性呢?
查找
在图书馆查阅专业书籍时,我发现了《C程序设计新思维》这边本书,在本书中的第十章 更好的结构中提到了ISO C99 标准中引入的3种语法:复合文字、可变参数宏、指定初始化值。之后,我在书中例 10-11 找出了我问题的最终答案。
分析
代码:
#include<stdio.h>
typedef struct{
double pressure, moles, temp;
} ideal_struct;
#define ideal_pressure(...) ideal_pressure_base((ideal_struct){.pressure=1, \
.moles=1, .temp=273.15, __VA_ARGS__})
double ideal_pressure_base(ideal_struct in){
return (8.314*in.moles*in.temp)/in.pressure;
}
int main(){
double x;
scanf("%lf",&x);
printf("volume given defaults: %g\n", ideal_pressure());
printf("volume given boiling temp: %g\n", ideal_pressure(.temp=373.15));
printf("volume given two moles: %g\n", ideal_pressure(.moles=x));
printf("volume given two boiling moles: %g\n", ideal_pressure(.moles=2, .temp=373.15));
}
解读:
因为一个函数的输入是参数固定的,而用户输入是可变的,显然C语言不允许我们直接使用可变参数。
- 我们可以先定义一个输入参数的结构体,把输入参数包装起来。
- 定义以这个结构体为输入参数的 func_base 函数接口,再通过可变参数宏来定义创建真正调用的 func 函数接口。
- 像使用可变参数函数一样,使用 func 函数,而 func_base 为普通C语言函数。两者都可以在代码中正常使用。
这个例子使用了ISO C99的以下两个特性:
-
可变参数宏:
实际效果类似于简单替换,把 func(...) 中省略号部分中的部分与后面 VA_ARGS 位置会发生原封不动地替换,在省略号中书写的部分就等于在 VA_ARGS 书写。 -
复合文字:
用 (){} 来对一个变量进行初始化。
()中书写变量类型。例:name_struct(结构体)、double[](浮点型数组)、 ...
{}中书写对应类型的值。例:.temp=273.15, .moles=2, ... 、1.5, 5.6, 7.9874, ... 、...
因为在宏内部已经通过复合文字这一C99语法给输入参数结构体所有成员赋值过一次,所需参数已经齐全,可以通过用户输入2次赋值参数,对参数进行调整,后续调用赋值相当于对结构体某一变量的二次赋值编译器并不会报错(见结果图)。
结果:
注意:
文章为本人在简书平台原创,盗用必究!