48

我已经用 C 和 C++ 编程了几年,现在我刚刚上了一门大学课程,我们的书有一个这样的功能,例如:

int foo(){
  int x=0;
  int y=20;
  return x,y; //y is always returned
}

我从未见过这样的语法。事实上,我从未见过在,参数列表之外使用的运算符。如果y总是返回,那有什么意义呢?是否存在需要像这样创建 return 语句的情况?

(此外,我也标记了 C,因为它适用于两者,尽管我的书专门是 C++)

4

18 回答 18

53

根据C 常见问题解答

准确地说,逗号运算符在一般表达式中的含义

e1,e2

是“计算子表达式 e1,然后计算 e2;表达式的值是 e2 的值。” 因此, e1 最好涉及赋值或递增 ++ 或递减 - 或函数调用或其他某种副作用,否则它会计算一个将被丢弃的值。

所以我同意你的看法,除了说明这是有效的语法之外没有其他意义,如果那样的话。

如果你想在 C 或 C++ 中返回这两个值,你可以创建一个struct包含xy成员,并返回结构:

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)
于 2010-03-29T16:16:19.273 回答
23

参数列表中的逗号只是用来分隔参数,与逗号运算符不同。逗号运算符,如您的示例所示,计算 x 和 y,然后丢弃 x。

在这种情况下,我猜想这是一个试图返回两个值的人的错误,并且不知道该怎么做。

于 2010-03-29T16:13:52.277 回答
20

逗号运算符主要用于for如下语句:

for( int i=0, j=10; i<10; i++, j++ )
{
    a[i] = b[j];
}

第一个逗号不是逗号运算符,它是声明语法的一部分。第二个逗号运算符。

于 2010-03-29T16:18:42.920 回答
9

这根本不能真正回答原始问题,但可能会引起某些人的兴趣,但是如果您希望它在 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);
于 2010-03-29T16:46:09.080 回答
8
 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

于 2010-03-29T16:27:47.127 回答
5

就像这里评论的每个人都认为这是毫无意义的,我不反对,只是看看这个例子,我会做出一个好不了多少的猜测:

作者收到了关于函数中未使用 x 的编译器警告,这是消除警告的一种简单方法。

于 2010-03-29T16:26:27.083 回答
4

这是逗号运算符 (,)

对表达式 x 和 y 都求值。整体表达式的结果是y,即后一个值。

很难说为什么在这里使用它。我想,出于演示目的。显然,该函数可以重构为:

int foo()
{
  return 20;
}
于 2010-03-29T16:13:32.933 回答
4

此语法可用于保存if- 语句的附加范围括号。例如,通常您会编写以下内容:

if (someThing == true)
{
    a = 1;
    b = 2;
    return true;
}

这可以替换为以下内容:

if (someThing == true)
    return a = 1, b = 2, true;

我认为这种编码风格的使用是出于摆姿势的冲动,而不是编写干净的代码。

于 2012-07-24T14:25:49.727 回答
3

这看起来像是一个糟糕的代码示例。它可能是 C/C++ 中的有效语法,但我想不出你想要这样做的原因。

如果你想返回 x 和 y,在 C++ 中更好的方法是定义一个带有 x 和 y 属性的“Point”类或结构,然后返回它。另一种选择是通过引用传入 x 和 y,然后在方法中适当地设置值。

如果该方法只返回 y,我将只“返回 y;”。如果 x 需要在 return 语句之前“评估”,它应该在单独的行上完成。

于 2010-03-29T16:18:55.637 回答
2

该 return 语句没有任何意义。

如果x被声明volatile,它将强制访问(因为至少在 C++ 中对volatile变量的引用被认为是外部可观察的行为),但事实并非如此。

如果,而不是x,有某种带有副作用的计算,它将执行该计算,然后返回y。然而,一个非volatile x没有副作用。该实现不需要执行任何没有副作用或外部可观察行为的代码。逗号运算符执行逗号左侧的任何内容,忽略结果,并执行并保留右侧的值(除了在这种情况下可以随意忽略运算符的左侧)。

因此,该return x, y;语句与return y;. 如果x不只是执行一个完全没有意义的事情,那么在风格上将它写成 会更好x; return y;,这是完全相同的事情。这样就不会那么混乱了。

于 2010-03-29T17:02:51.380 回答
1

在 for 循环之外,这个 comman 运算符的另一个主要用户(与函数调用版本相对)是在执行某些操作后返回值的宏中。这些是现在执行此操作的其他方法,但我认为命令运算符曾经是最干净的方法。

#define next(A, x, y, M) ((x) = (++(y))%(M) , A[(x)])

请注意,这个宏通常是一个不好的宏示例,因为它重复 x 并且可能出于其他原因。以这种方式使用逗号运算符应该很少见。您书中的示例可能是试图使代码示例适合该示例可用的行数。

于 2010-03-29T19:07:00.260 回答
1

一方面,这可能是作者的一个诚实的错误。

另一方面,作者可能正在解释语法正确的正确代码,而不是编译器警告。

无论哪种方式,返回多个结果的唯一方法是定义一个类并使用它的实例,或者可能是一个数组或集合。

于 2010-03-29T16:41:27.737 回答
1

这是逗号运算符。这种语法可用于禁用编译器关于未使用变量的警告x

于 2010-03-29T17:08:47.770 回答
0

这本书试图消除那些在 C++ 之前学习其他语言的人的潜在困惑。在许多语言中,您可以使用类似的语法返回多个值。在 C++ 中,它会在没有警告的情况下编译(除非您指定-Wallor -Wunused-value),但如果您习惯于那些其他语言,它不会像您期望的那样工作。它只会返回最后一个值。

然而,似乎作者造成的混乱比他防止的要多,因为在 C++ 的 return 语句中使用这种语法没有可读的情况,除非像另一种语言一样意外地使用它。他警告大多数人不会尝试使用的用法。但是,如果你这样做了,调试起来会非常混乱,因为多重赋值语句int x, y = foo()也可以很好地编译。

底线:始终使用-Wall并修复它警告您的内容。C++ 语法允许您编写许多没有意义的东西。

于 2014-06-26T15:27:53.650 回答
0

我已经看到在 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;

}
于 2013-09-11T09:41:21.793 回答
0

是否存在需要像这样创建 return 语句的情况?

IMO,我永远不会在像本书示例这样的函数中使用多个返回。它违反了结构化设计。尽管如此,还是有很多程序员这样做!调试别人的代码 我在每个 return 语句中都为一个全局变量赋值,这样我就可以找出执行了哪个 return。

于 2010-09-25T12:08:03.013 回答
0

当与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
于 2016-01-07T01:34:58.837 回答
0

如果 y 总是返回,那有什么意义呢?

关键是 x 的副作用(即逗号运算符的左侧)。有关详细信息,请参见例如 Justin Ethier 的答案。

是否存在需要像这样创建 return 语句的情况?

一个例子是 C++11 到 C++14 中的 constexpr 函数:这样的函数可能不包含任意语句,但恰好包含一个 return 语句。

这是来自Patrice Roys 在 CppCon 2016 上的“异常情况”的代码示例:

constexpr int integral_div(int num, int denom) {
    return assert(denom != 0), num / denom;
}
于 2016-10-30T22:07:28.673 回答