C++-C++为什么不支持元组作为函数返回值

C++-C++为什么不支持元组作为函数返回值

偏爱自由 发布于 2017-04-05 字数 296 浏览 1090 回复 10

用C++写程序的时候,最郁闷的就是我想要返回两个值,必须构造一个结构体来返回,或者一个通过返回值,另外一个通过引用传递参数。而其他语言比如python, erlang却支持。

在stack overflow也看到了这个问题
http://stackoverflow.com/questions/321068/returning-multiple-values-from-a-c-function

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(10

瑾兮 2017-11-12 10 楼

1.想像中C语言如何支持函数有可变数量返回值
目前的编译器不支持,但是要给编译器加一种call的方式,让这种call支持返回多个返回值也是有可能的
比如我们增加一种 _ _klcall,这种函数把返回个数放在堆栈 - 0xc处,再之后是第一个返回值,之后是第二个。。。
这样的c语言代码

_ _klcall int,int addsub(int a,int b)
{
return (a + b),(a -b)
}
int i,j = addsub(5,6);i == 11,j == -1

假设新的编译器支持这种 _ _klcall产生的汇编代码

;;函数
;;__klcall int,int addsub(int a,int b)
;;{
;; return (a + b),(a -b)
;;}
;汇编代码
push ebp
mov ebp,esp
push ebx
mov eax,dword ptr ss:[ebp+0x8];参数1
add eax,dword ptr ss:[ebp+0xC];参数1 + 参数2
mov ebx,eax
mov eax,dword ptr ss:[ebp+0x8];参数1
add eax,dword ptr ss:[ebp+0xC];参数1 - 参数2
;add结果在ebx sub结果在eax
;现在开始输出。从 [ebp - 0x4]开始.因为[ebp]里保存的是调用前的ebp不能破坏
mov dword ptr[ebp - 0x4], 2;先输出共返回两个参数
mov dword ptr[ebp - 0x8], ebx;再输出返回add结果
mov dword ptr[ebp - 0xc],eax;再输出返回sub结果
pop ebx
pop ebp
retn 8

;;调用
;;int i,j = addsub(5,6);i == 11,j == -1
;;汇编代码
push 0x5
push 0x6
call funAddSubAddres
;;这时esp指向0x5; [esp - 4]是上一个调用call的下一个地址,[esp - 8]是保留的ebp值,就是上面说不能破坏那个
mov eax,[esp - 0xc]//上个调用共返回多少个函数
mov [ebp - 0x4], [esp - 0x10]//add的结果 == 11
mov [ebp - 0x8], [esp - 0x14]//sub的结果 == -1
;这时堆栈应该是这样的
; 0012FDD8 ffffffff;sub的结果-1
; 0012FDDC 0000000b;add的结果11
; 0012FDE0 00000002;返回两个返回值
; 0012FDE4 /0012FF08; 调用时的ebp
; 0012FDE8 |00411556; 返回到 call funAddSubAddres 的下一语句
;esp 指向这里->0012FDEC |00000005;
; 0012FDF0 |00000006

2.从以上假想代码来看,要让函数支持多个返回值,也很简单,效率我也看不出有多大问题。如果把返回个数放在eax里返回,代码还可以再少一些。
3.所以我觉得之所以现代c函数不支持多个返回值,是因为编译器厂商没觉得有那必要。
如果想要这种 local a,b = subadd(5,6)这种这么方面的特性,那直接用脚本好了比如lua,python.
4.现在做游戏,特别是客户端游戏,如果不用脚本直接用c++,会让很多人把嘴张得大大的:怎么可能?其实还是淫者见淫

偏爱自由 2017-10-31 9 楼

有二种方法可以解决

通过std::pair<one, two>来解决
更灵活的方式可以通过boost::Tuple

甜柠檬 2017-10-04 8 楼

你的意思是语法上想这么写:

 a, b, c = f();

这的确是一种语法上的便利性。实际上函数中最终有一个return,返回一个元组“对象”。它不是数组这种简单的“同一的多个对象”,所以这个对象能存放多种类型的对象,那么C++就必须为没个对象内置"运行期识别"的类型识别,包括内置对象,你觉得可能吗。这是一个高级对象,C++语言设计目的之一就是只引入基本的内置类型,用户需要的高级类型需要自己构造。

浮生未歇 2017-09-27 7 楼

我觉得从汇编角度讨论这个问题可能不太好,这和C++语言是一种强类型语言有关。
在Python中,它是一种弱类型语言,一个元组中存放的可以是任何类型;而在C++中和元组最相近的vector中的元素必须是同一类型。
如果返回值是多个同类型值,比如是2个int数,那么C++可以用vector返回;但是如果是不同类型就不行了。
每个语言都有自己的长处,要善于选择使用语言。

晚风撩人 2017-09-22 6 楼

pair很好 如果要返回多个参数boost里有很多方案可用

泛泛之交 2017-08-28 5 楼

这个问题好大,python我不太懂还是从C++方面来说吧
C++最早引入对象模型的时候,语言的设计专家们已经在此基础上做了很多优化,但局部的编译生成的代码,也因为封装牺牲了空间和时间,设计者和编译器的构建人员为了C++的高效性,尽量减少语言在因为引入封装而带来的成本,最早的Stroustrup设计的简单对象模型发展到现在已经做了很多的优化,C++定义了对象的语法,但没有引入特定的对象作为语法的部分,我想还是考虑到效率的原因,函数的返回值在函数语义学上,构造一个返回语法支持的对象的函数,和一个返回值的函数,估计整个语法编译器都要重新设计。
每种语言都有自己的特长,应该是越高级的语言使用越方便,但因为方便而带来的是空间和时间的成本。

浮生未歇 2017-08-18 4 楼

终于想明白为什么C/C++只能返回一个值,而其他的脚本语言可以返回多个值了。c++在编译成汇编语言中,约定返回值用eax保存,并且只能保存一个值,除非改汇编指令。

 int add(int a, int b)
{
return a + b;
}

int process()
{
int value = 0;
__asm
{
push eax
push 2
push 3
call add
add esp, 8
mov value, eax
pop eax
}
return 1;
}

浮生未歇 2017-08-05 3 楼

主要还是没有设计这个编译器功能吧,
{min,max} = find_min_max(...)
相同的功能完全可以写成
void find_min_max(..., &min, &max);
或者用引用
void find_min_max(..., min, max);
没有必要为这种情况定义一种语法,只会导致混乱。

晚风撩人 2017-07-17 2 楼

我以前看python的书说
python 中的元组 貌似是防止 错误修改 才搞的
c++ 里边可以定义 不可修改的 结构或者类型

夜无邪 2017-05-22 1 楼

C++是通过把返回值放置在EAX里面来获取返回值的,所以只能存放一个值(包括指针等等)