Home  >  Article  >  Backend Development  >  为什么C/C++或Java中函数不能返回多个值,而像Matlab和一些脚本语言可以?

为什么C/C++或Java中函数不能返回多个值,而像Matlab和一些脚本语言可以?

WBOY
WBOYOriginal
2016-06-06 16:23:251148browse

不要说什么用传引用或者指针实现,那也是返回一个值

回复内容:

这是std::tie被忽略得最惨的一次 看了前面的回答想提一点:做“真的多返回值”的语言(实现)不是没有。
真的“返回多值”的语言有例如Lua:Programming in Lua : 5.1
它利用操作数栈的灵活性,把返回值全部放在操作数栈上返回。这跟“返回一个tuple”的做法最显著的不同是,tuple是一个额外的实体,而Lua这种做法没有一个额外的实体来包装多返回值。

至于题主原本的问题, 我认同@赵劼的回答,大家可以随便推测,但最原始的设计决定到底是怎么回事只有当时的设计者才知道。

C++最常见的返回多值的方式,要么是返回tuple,要么更传统的是用out参数来返回多值(换言之,传入&参数或显式指针)。 std::tuple func1()
{
return {1,2};
}

void func2()
{
int a,b;
std::tie(a,b)=func1();
}
这样凑合一下吧 one is more,多个值,也就是一个集合而已。 针对有说返回多个值仅仅是语法糖的言论,提出反对。
返回多个值就实现而言,可能是语法糖,可能是性能提升的工具

语法糖而言,也就是实现上相当于C/C++中传递一个struct *,然后将return value一个个存入struct中,调用者再选择使用。只是从语法层次上支持更简便(?)的写法

而性能提升方面则比较复杂,需要对汇编以及一些基础算法(操作)有入门认识。
简单说,如果我们传递一个struct *,编译器不一定能优化内存读写部分,那么反而无论我们使不使用所有返回值,这个函数都要去写满struct,反而带来性能损失。
而如果实现是用寄存器或其他平台特性来返回多个值,则不存在上面所说的问题

以下长篇大论
----------------------------
在C/C++以及绝大多数语言中,我们有两个运算符—— / 和 %,整除(DIV)和取模(求余/MOD)
在Intel平台上,这两个运算是用一条指令实现的,这里以unsigned形式的IDIV为例(下面参考页面用bing随手搜的):
Intel Pentium CPU Instruction Set Reference
写法为 IDIV oprand

这个指令将R2:R0组成的DOUBLE WORD作为被除数,操作数oprand作为除数,进行除法计算,结果商存入R0,余数存入R2。
在C/C++中,如果你写:
<code class="language-c"><span class="kt">unsigned</span> <span class="n">c</span> <span class="o">=</span> <span class="n">a</span><span class="o">/</span><span class="n">b</span><span class="p">;</span>
<span class="kt">unsigned</span> <span class="n">r</span> <span class="o">=</span> <span class="n">a</span><span class="o">%</span><span class="n">b</span><span class="p">;</span>
</code>
没为啥。图简单呗
不过这确实是个有趣的现象:绝大部分程序语言都说仿照数学函数的定义,一个函数就该只返回一个值,向数学学习的;而大名鼎鼎的矩阵实验室Matlab,却支持函数多返回值。 函数只返回一个值的话,那么函数调用就是一个表达式,可以用作参数调用其他函数:
<code class="language-text">g(f(x))
h(f(y))
</code>
go支持返回多个值,函数签名里写的是多个类型,不是tuple之类,实现也和lua的类似,不需要额外的包装,不是语法糖(因为并不是返回一个struct,没有对应的无糖做法)。所以这和静态类型、脚本语言什么的没有关系,只是设计理念不同而已。
go可以这样写:
<code class="language-go"><span class="kn">package</span> <span class="nx">main</span>

<span class="kd">func</span> <span class="nx">main</span><span class="p">()</span> <span class="p">{</span>
	<span class="nx">fn</span> <span class="o">:=</span> <span class="kd">func</span><span class="p">(</span><span class="nx">a</span><span class="p">,</span> <span class="nx">b</span> <span class="kt">int</span><span class="p">)</span> <span class="p">(</span><span class="kt">int</span><span class="p">,</span> <span class="kt">int</span><span class="p">)</span> <span class="p">{</span>
		<span class="k">return</span> <span class="nx">a</span><span class="p">,</span> <span class="nx">b</span>
	<span class="p">}</span>
	<span class="nx">fn</span><span class="p">(</span><span class="nx">fn</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">))</span>
<span class="p">}</span>
</code>
认为 @yf zpy说的是语法糖的.
可以简单的看下CoffeeScript的编译前后的代码.
coffee代码:
[a, b, c] = fun()
编译后的js代码:
<code class="language-text">var a, b, c, _ref;

_ref = fun(), a = _ref[0], b = _ref[1], c = _ref[2];
</code>
返回多值?只不过是返回元组再赋值解构的语法糖而已。C++照样能做:

<code class="language-text">#include <tuple>
#include <string>
#include <stdexcept>
using namespace std;

tuple<double char string> get_student(int id)
{
    if (id == 0) return make_tuple(3.8, 'A', "Lisa Simpson");
    if (id == 1) return make_tuple(2.9, 'C', "Milhouse Van Houten");
    if (id == 2) return make_tuple(1.7, 'D', "Ralph Wiggum");
    throw invalid_argument("id");
}

int main()
{
    double gpa1;
    char grade1;
    string name1;
    tie(gpa1, grade1, name1) = get_student(1);

    return 0;
}
</double></stdexcept></string></tuple></code>
Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn