我已经用 C 和 C++ 编程了几年,现在我刚刚上了一门大学课程,我们的书有一个这样的功能,例如:
int foo(){
int x=0;
int y=20;
return x,y; //y is always returned
}
我从未见过这样的语法。事实上,我从未见过在,
参数列表之外使用的运算符。如果y
总是返回,那有什么意义呢?是否存在需要像这样创建 return 语句的情况?
(此外,我也标记了 C,因为它适用于两者,尽管我的书专门是 C++)
我已经用 C 和 C++ 编程了几年,现在我刚刚上了一门大学课程,我们的书有一个这样的功能,例如:
int foo(){
int x=0;
int y=20;
return x,y; //y is always returned
}
我从未见过这样的语法。事实上,我从未见过在,
参数列表之外使用的运算符。如果y
总是返回,那有什么意义呢?是否存在需要像这样创建 return 语句的情况?
(此外,我也标记了 C,因为它适用于两者,尽管我的书专门是 C++)
根据C 常见问题解答:
准确地说,逗号运算符在一般表达式中的含义
e1,e2
是“计算子表达式 e1,然后计算 e2;表达式的值是 e2 的值。” 因此, e1 最好涉及赋值或递增 ++ 或递减 - 或函数调用或其他某种副作用,否则它会计算一个将被丢弃的值。
所以我同意你的看法,除了说明这是有效的语法之外没有其他意义,如果那样的话。
如果你想在 C 或 C++ 中返回这两个值,你可以创建一个struct
包含x
和y
成员,并返回结构:
struct point {int x; int y;};
然后,您可以定义一个类型和辅助函数,以允许您轻松地返回以下两个值struct
:
typedef struct point Point;
Point point(int xx, int yy){
Point p;
p.x = xx;
p.y = yy;
return p;
}
然后更改您的原始代码以使用辅助函数:
Point foo(){
int x=0;
int y=20;
return point(x,y); // x and y are both returned
}
最后,您可以尝试一下:
Point p = foo();
printf("%d, %d\n", p.x, p.y);
此示例在 C 和 C++ 中编译。虽然,正如 Mark 下面建议的那样,在 C++ 中,您可以为point
结构定义一个构造函数,从而提供更优雅的解决方案。
附带说明一下,直接返回多个值的能力在支持它的 Python 等语言中非常棒:
def foo():
x = 0
y = 20
return x,y # Returns a tuple containing both x and y
>>> foo()
(0, 20)
参数列表中的逗号只是用来分隔参数,与逗号运算符不同。逗号运算符,如您的示例所示,计算 x 和 y,然后丢弃 x。
在这种情况下,我猜想这是一个试图返回两个值的人的错误,并且不知道该怎么做。
逗号运算符主要用于for
如下语句:
for( int i=0, j=10; i<10; i++, j++ )
{
a[i] = b[j];
}
第一个逗号不是逗号运算符,它是声明语法的一部分。第二个是逗号运算符。
这根本不能真正回答原始问题,但可能会引起某些人的兴趣,但是如果您希望它在 C++ 中返回两者,则需要像这样编写它(并且需要一个 c++0x 编译器)
tuple<int, int> foo()
{
int x = 0;
int y = 20;
return make_tuple(x, y);
}
像这样访问它 -
tuple<int, int> data = foo();
int a = get<0>(data);
int b = get<1>(data);
struct Point {
int x, y;
Point(int x_) : x(x_), y(0) {}
Point(const Point& p) : x(p.x), y(p.y) {}
Point operator, (int y_) const { Point p=*this; p.y = y_; return p; }
};
Point get_the_point () {
int x = 0;
int y = 20;
return (Point)x, y;
}
:p
就像这里评论的每个人都认为这是毫无意义的,我不反对,只是看看这个例子,我会做出一个好不了多少的猜测:
作者收到了关于函数中未使用 x 的编译器警告,这是消除警告的一种简单方法。
这是逗号运算符 (,)。
对表达式 x 和 y 都求值。整体表达式的结果是y,即后一个值。
很难说为什么在这里使用它。我想,出于演示目的。显然,该函数可以重构为:
int foo()
{
return 20;
}
此语法可用于保存if
- 语句的附加范围括号。例如,通常您会编写以下内容:
if (someThing == true)
{
a = 1;
b = 2;
return true;
}
这可以替换为以下内容:
if (someThing == true)
return a = 1, b = 2, true;
我认为这种编码风格的使用是出于摆姿势的冲动,而不是编写干净的代码。
这看起来像是一个糟糕的代码示例。它可能是 C/C++ 中的有效语法,但我想不出你想要这样做的原因。
如果你想返回 x 和 y,在 C++ 中更好的方法是定义一个带有 x 和 y 属性的“Point”类或结构,然后返回它。另一种选择是通过引用传入 x 和 y,然后在方法中适当地设置值。
如果该方法只返回 y,我将只“返回 y;”。如果 x 需要在 return 语句之前“评估”,它应该在单独的行上完成。
该 return 语句没有任何意义。
如果x
被声明volatile
,它将强制访问(因为至少在 C++ 中对volatile
变量的引用被认为是外部可观察的行为),但事实并非如此。
如果,而不是x
,有某种带有副作用的计算,它将执行该计算,然后返回y
。然而,一个非volatile
x
没有副作用。该实现不需要执行任何没有副作用或外部可观察行为的代码。逗号运算符执行逗号左侧的任何内容,忽略结果,并执行并保留右侧的值(除了在这种情况下可以随意忽略运算符的左侧)。
因此,该return x, y;
语句与return y;
. 如果x
不只是执行一个完全没有意义的事情,那么在风格上将它写成 会更好x; return y;
,这是完全相同的事情。这样就不会那么混乱了。
在 for 循环之外,这个 comman 运算符的另一个主要用户(与函数调用版本相对)是在执行某些操作后返回值的宏中。这些是现在执行此操作的其他方法,但我认为命令运算符曾经是最干净的方法。
#define next(A, x, y, M) ((x) = (++(y))%(M) , A[(x)])
请注意,这个宏通常是一个不好的宏示例,因为它重复 x 并且可能出于其他原因。以这种方式使用逗号运算符应该很少见。您书中的示例可能是试图使代码示例适合该示例可用的行数。
一方面,这可能是作者的一个诚实的错误。
另一方面,作者可能正在解释语法正确的正确代码,而不是编译器警告。
无论哪种方式,返回多个结果的唯一方法是定义一个类并使用它的实例,或者可能是一个数组或集合。
这是逗号运算符。这种语法可用于禁用编译器关于未使用变量的警告x
。
这本书试图消除那些在 C++ 之前学习其他语言的人的潜在困惑。在许多语言中,您可以使用类似的语法返回多个值。在 C++ 中,它会在没有警告的情况下编译(除非您指定-Wall
or -Wunused-value
),但如果您习惯于那些其他语言,它不会像您期望的那样工作。它只会返回最后一个值。
然而,似乎作者造成的混乱比他防止的要多,因为在 C++ 的 return 语句中使用这种语法没有可读的情况,除非像另一种语言一样意外地使用它。他警告大多数人不会尝试使用的用法。但是,如果你这样做了,调试起来会非常混乱,因为多重赋值语句int x, y = foo()
也可以很好地编译。
底线:始终使用-Wall
并修复它警告您的内容。C++ 语法允许您编写许多没有意义的东西。
我已经看到在 C 中使用这种语法在操作中途返回时进行内务处理。绝对不可维护的代码:
int foo(int y){
char *x;
x = (char*)malloc(y+1);
/** operations */
if (y>100) return free(x),y;
/** operations */
if (y>1000) return free(x),y;
}
是否存在需要像这样创建 return 语句的情况?
IMO,我永远不会在像本书示例这样的函数中使用多个返回。它违反了结构化设计。尽管如此,还是有很多程序员这样做!调试别人的代码 我在每个 return 语句中都为一个全局变量赋值,这样我就可以找出执行了哪个 return。
当与return
关键字一起使用时,逗号运算符返回最后一个值,这最初是令人困惑的,但可以使事情更简洁。
例如,以下程序将以状态码 2 退出。
#include <iostream>
using namespace std;
void a() {
cout << "a" << endl;
}
int one() {
cout << "one" << endl;
return 1;
}
int zero() {
cout << "zero" << endl;
return 0;
}
int main() {
return one(), a(), zero(), 2;
}
使用以下命令编译和执行时,您将看到下面的输出。
michael$ g++ main.cpp -o main.out && ./main.out ; echo $?
one
a
zero
2
关键是 x 的副作用(即逗号运算符的左侧)。有关详细信息,请参见例如 Justin Ethier 的答案。
一个例子是 C++11 到 C++14 中的 constexpr 函数:这样的函数可能不包含任意语句,但恰好包含一个 return 语句。
这是来自Patrice Roys 在 CppCon 2016 上的“异常情况”的代码示例:
constexpr int integral_div(int num, int denom) {
return assert(denom != 0), num / denom;
}