【问题标题】:C++ -- return x,y; What is the point?C++ -- 返回 x,y;重点是什么?
【发布时间】:2011-02-02 03:00:44
【问题描述】:

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

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

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

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

【问题讨论】:

  • 这是出自哪本书?我无法想象这样做的任何正当理由。
  • “D. Malik,C++ 编程:包括数据结构的程序设计,第四版。Course Technology Incorporated,2007,ISBN 1-4188-3640-0”我不推荐任何人,因为作者似乎没有牢牢掌握 C++ 中提到的诸如“无论如何,变量声明总是位于函数的顶部”之类的东西。
  • 把书扔掉。
  • @Daniel,我真希望我能,但这是获得大学学分所必需的
  • @Frank V:即使这样也没有意义——变量超出了范围。 @Earlz:这是否只是为了证明这 not 返回两个值?举例说明不该做什么?

标签: c++ c syntax return-value comma-operator


【解决方案1】:

这是逗号运算符 (,)

表达式 x 和 y 都被计算。整体表达式的结果是y,即后者的值。

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

int foo()
{
  return 20;
}

【讨论】:

  • @mmyers:这里给出的答案是......似乎没有任何意义。
  • @Jefromi:我评论的时候不在那里。
【解决方案2】:

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

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

【讨论】:

    【解决方案3】:

    根据C FAQ

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

    e1,e2

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

    所以我同意你的观点,没有意义除了说明这是有效的语法,如果那样的话。

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

    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)
    

    【讨论】:

    • 感谢运营商的解释。
    • 你的 point 结构需要一个带有两个 int 参数的构造函数。
    • @Mark - struct 只是一个例子 - 也就是说,您愿意详细说明吗?严格来说,C 中没有构造函数。无论如何,代码在 C 和 C++ 中编译得很好,并且可以通过代码直接访问 xy 成员。
    • 在 C 中你是对的,没有构造函数是可能的。在 C++ 中,构造函数允许您执行 return point(x,y);。抱歉这么神秘。
    • 我想指出你在没有意义的情况下提出的观点让我很开心。
    【解决方案4】:

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

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

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

    【讨论】:

    • 这毫无意义。为什么这个答案被赞成,为什么这个答案被选为正确的!它与提出的问题完全无关。
    • 在这种情况下,需要使用逗号来增加ij。在其他情况下,如果您想强调两个语句确实紧密相关且不应拆分,则可以使用逗号而不是分号。例如std::memcpy(data, moredata, moresize), datasize+=size;。我喜欢将这些语句放在一起,以避免有人意外移动或擦除第二部分。
    • @Joel:如果您收回投票/接受的答案,则可以获得徽章。
    • 我把问题背后的问题理解为“为什么要有逗号运算符?”而不是“为什么在退货声明中有一个?”显然 OP 同意这是他真正的问题。
    【解决方案5】:

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

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

    如果方法只返回 y,我只会“返回 y;”。如果需要在 return 语句之前对 x 进行“评估”,则应在单独的行中完成。

    【讨论】:

      【解决方案6】:

      就像这里评论的每个人都认为这是没有意义的,我不反对,只是看这个例子,我会猜测这并没有好多少:

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

      【讨论】:

      • 我刚用g++试过这个,如果你用-Wall会有一个警告。我不确定是赞扬作者在将代码放入书中之前编译代码还是谴责作者提出这个解决方案。不过,如果作者真的以此为契机讨论编译器警告等问题,那可能会很有趣。
      • 我收回了。我刚刚尝试了给定的代码,但仍然发出警告。也许他在使用不同的编译器。
      • 他还有一本关于 Java 的书(那里有一个红旗)所以可能使用 MVC++
      • 似乎 VS6.0 可能是候选者,它确实给出了警告 C4189:如果删除了“x”,则局部变量已初始化但不会被引用,前提是警告设置为级别 4(最高)。
      • 如果这是作者的意图,那是个坏主意……编写看起来像返回两个值的代码,而实际上它只返回一个值弊大于利。跨度>
      【解决方案7】:
       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

      【讨论】:

      • 那不是 C++。我的意思是,它会编译,但这太不可读了。伊克。
      • @clahey:那你会讨厌这个:boost.org/doc/libs/1_42_0/libs/assign/doc/index.html
      • 我认为提升的东西肯定是有问题的,但你所拥有的东西更糟糕。例如:“返回(点)1、2、3;”返回 (1,3)。 "return (Point)1" 返回 (1,0)。这些都不像直觉的行为。此外,您的符号不会保存任何内容。如果你只是声明一个需要两个整数的正确构造函数,你可以写“return Point(x, y);”它甚至不保存一个打字字符,并且更具可读性。提升的东西至少节省了大量的打字。
      • @clahey:请注意,我并不是在提倡这种风格(参见“:p”?),我只是在展示一个逗号操作符被滥用的“点”(我可以'不要放置多行注释)。
      • 这真是太奇妙了邪恶。是否有 C++ 的 IOCCC 等价物?
      【解决方案8】:

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

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

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

      【讨论】:

        【解决方案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);
        

        【讨论】:

        • 就个人而言,我更喜欢:int a = 0, b = 0;领带(a,b) = foo();
        • 我不知道 tie,我得试试看。
        • 在 C++03 编译器中,只返回一个 pair。当然,这并不能直接推广到两个以上的值。
        【解决方案10】:

        return 语句没有任何意义。

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

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

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

        【讨论】:

        • 即使x 被一些具有副作用的表达式替换,像这样将它塞进return 语句也是没有意义的。只需单独声明:expr_with_side_effects; return y;.
        • 通常:是的,读起来更清晰。但是 constexpr 函数(在 C++14 之前)呢?
        【解决方案11】:

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

        【讨论】:

          【解决方案12】:

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

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

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

          【讨论】:

            【解决方案13】:

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

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

            【讨论】:

            • 该示例与多个return语句无关。
            【解决方案14】:

            此语法可用于保存if- 语句的附加范围括号。例如。通常你会写如下:

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

            这可以替换为以下内容:

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

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

            【讨论】:

            • 嘿。这是一个……有趣的用例
            • 我不认为这样做的动机通常来自他想摆姿势,而是希望通过逐渐节省读者垂直滚动工作的时间来提高代码的可读性
            【解决方案15】:

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

            【讨论】:

              【解决方案16】:

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

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

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

              【讨论】:

                【解决方案17】:

                当与 return 关键字一起使用时,逗号运算符返回 last 值,这最初是令人困惑的,但可以使事情更简洁.

                例如,以下程序将以状态码 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
                

                【讨论】:

                  【解决方案18】:

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

                  该点是 x 的副作用(即逗号运算符的左侧)。参见例如Justin Ethier 详细回答。

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

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

                  这是来自Patrice Roys “The Exception Situation" at CppCon 2016的代码示例:

                  constexpr int integral_div(int num, int denom) {
                      return assert(denom != 0), num / denom;
                  }
                  

                  【讨论】:

                    猜你喜欢
                    • 1970-01-01
                    • 1970-01-01
                    • 2019-12-23
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    相关资源
                    最近更新 更多