众所周知,C语言里头的函数是只能有一个返回值的。不过我们可以自己写一个头文件,实现C函数的多返回值。
成品大概是这样一个效果:
#include <stdio.h>
#include "return.h" // 我们将要自定义的文件
mul func(input1, input2, ...){
......
remul(with output1, with output2, ...); //remul == return multiple
}
int main(){
......
from func(input1, input2, ...) to (val1, type) to (val2, type) to ...;
......
}
下面我大致地演示一下具体实现过程:
假如我们现在定义了一个函数,需要同时返回多个值,假设就是a,b,c三个变量,那么我们可以创建一个数组,在其中存储这三个变量的指针,然后将数组返回。
一个指针的长度为8个字节,是一个long long型数据,所以这个函数的返回值类型为long long *
long long * func(){
}
然后我们创建一个long long型数组,取各变量指针并强制转换为long long型数据,再将数组返回,就像这样:
long long * func(){
......
long long ptr_arr[] = {(long long)&a, (long long)&b, (long long)&c};
return ptr_arr;
}
这是一段很庞杂的代码,不便书写,所以我们要用预编译语句对其进行简化
#define mul long long * //将所有“mul”替换成“long long * ”
#define with (long long)& //将所有“with”替换成“(long long)&”
这样代码就可以简化如下:
mul func(){
......
long long ptr_arr[] = {with a, with b, with c};
return ptr_arr;
}
再定义一个预编译语句,对代码进行整体简化:
//括号中的省略号表示不定参数
//“__VA_ARGS__”会被替换成括号中输入的内容
//反斜线(“\”)表示连接上下两行预编译指令
#define remul(...) long long ptr_arr[] = {__VA_ARGS__};\
return ptr_arr
mul func(){
......
remul(with a, with b, with c);
}
ptr_arr这个变量名显得有些随意,换个正式点的
#define remul(...) long long __POINTERS_ARR__[] = {__VA_ARGS__};\
return __POINTERS_ARR__
接下来,我们需要在函数外接收这个数组,并对对应变量赋值:
long long * arr_ptr = func();
int val1 = *(int *)*(arr_ptr+0);
int val2 = *(int *)*(arr_ptr+1);
int val3 = *(int *)*(arr_ptr+2);
稍微有点绕。*(arr_ptr+i)是读取这个数组对应位置的long long型数据,(int *)*(arr_ptr+i)是将这个long long型数据转换成一个int类型的指针,*(int *)*(arr_ptr+i)是将这个指针里的值取出来,赋给等号左边。(只是拿int型做个例子,事实上任何数据类型都可以)
给它加个计数器:
int counter = 0;
long long arr_ptr = func();
int val1 = *(int *)*(arr_ptr+counter);
counter++;
int val2 = *(int *)*(arr_ptr+counter);
counter++;
int val3 = *(int *)*(arr_ptr+counter);
counter++;
我们发现,这段代码可以抽象成这种形式:
int counter = 0; long long arr_ptr = func()
; int val1 = *(int *)*(arr_ptr+counter); counter++
; int val2 = *(int *)*(arr_ptr+counter); counter++
; int val3 = *(int *)*(arr_ptr+counter); counter++
;
定义如下预编译指令:
#define from\
int counter = 0; long long arr_ptr =
#define to(value, type)\ //传入待赋值变量及其类型
; int value = *(type *)*(arr_ptr+counter); counter++
原代码简化成如下形式:
from func() to (val1, int) to (val2, int) to (val3, int);
这样一来就差不多完成了。
整合一下预编译指令:
#define mul long long *
#define with (long long)&
#define remul(...) long long __POINTERS_ARR__[] = {__VA_ARGS__};\
return __POINTERS_ARR__
#define from\
int counter = 0; long long arr_ptr =
#define to(value, type)\
; int value = *(type *)*(arr_ptr+counter); counter++
发现还有个问题,那就是每次执行的都是“int counter”“int value”的指令,这样这两个变量就有被重复定义的风险。我们将它们的定义挪到前头:
int value;
int counter = 0;
#define mul long long *
#define with (long long)&
#define remul(...) long long __POINTERS_ARR__[] = {__VA_ARGS__};\
return __POINTERS_ARR__
#define from\
counter = 0; long long arr_ptr =
#define to(value, type)\
; value = *(type *)*(arr_ptr+counter); counter++
成品如下,你可以将其定义为一个头文件,在自己的项目中导入
int __POINTER_ARR_COUNTER__ = 0;
long long * __ARR_POINTER__;
#define mul long long *
#define with (long long)&
#define remul(...)\
long long __POINTERS_ARR__[] = {__VA_ARGS__};\
return __POINTERS_ARR__
#define from __POINTER_ARR_COUNTER__ = 0;\
__ARR_POINTER__ =
#define to(val, type) ;\
val = *(type *)*(__ARR_POINTER__+__POINTER_ARR_COUNTER__);\
__POINTER_ARR_COUNTER__++