wake-up-neo.com

C++ - return x, y; Was ist der Sinn?

Ich programmiere seit ein paar Jahren in C und C++ und jetzt mache ich gerade einen College-Kurs und unser Buch hatte eine Funktion wie diese als Beispiel:

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

Ich habe noch nie eine solche Syntax gesehen. Tatsächlich habe ich den außerhalb von Parameterlisten verwendeten Operator , noch nie gesehen. Wenn y immer zurückgegeben wird, worum geht es dann? Gibt es einen Fall, in dem eine solche return-Anweisung erstellt werden müsste?

(Ich habe auch C markiert, weil es für beide gilt, obwohl mein Buch speziell C++ ist.)

46
Earlz

Der Komma-Operator wird hauptsächlich in for-Anweisungen verwendet:

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

Das erste Komma ist kein Kommaoperator, es ist Teil der Deklarationssyntax. Das zweite ist ein Kommaoperator.

20
Joel

Nach dem C FAQ :

Genau gesagt, die Bedeutung des Kommaoperators im allgemeinen Ausdruck

e1, e2

ist "werte den Unterausdruck e1 aus, dann werte e2 aus; der Wert des Ausdrucks ist der Wert von e2." Daher sollte e1 besser eine Zuweisung oder ein Inkrement ++ oder Decrement- oder Funktionsaufruf oder eine andere Art von Nebeneffekt beinhalten, da sonst ein Wert berechnet würde, der verworfen würde. 

Also stimme ich dir zu, es hat keinen Sinn Anders als zu veranschaulichen, dass dies eine gültige Syntax ist, falls dies der Fall ist. 

Wenn Sie beide Werte in C oder C++ zurückgeben möchten, können Sie eine struct mit x- und y-Mitgliedern erstellen und stattdessen die Struktur zurückgeben:

struct point {int x; int y;};

Sie können dann einen Typ und eine Hilfsfunktion definieren, um beide Werte innerhalb der Variablen struct einfach zurückzugeben:

typedef struct point Point;

Point point(int xx, int yy){
  Point p;
  p.x = xx;
  p.y = yy;
  return p;
}

Und ändern Sie dann Ihren ursprünglichen Code, um die Hilfsfunktion zu verwenden:

Point foo(){
  int x=0;
  int y=20;
  return point(x,y); // x and y are both returned
}

Und zum Schluss können Sie es ausprobieren:

Point p = foo();
printf("%d, %d\n", p.x, p.y);

Dieses Beispiel wird in C und C++ kompiliert. Wie Mark im Folgenden vorschlägt, können Sie in C++ einen Konstruktor für die point-Struktur definieren, der eine elegantere Lösung bietet.


Nebenbei bemerkt ist die Möglichkeit, mehrere Werte direkt zurückzugeben, in Sprachen wie Python, die dies unterstützen, eine wunderbare Eigenschaft:

def foo():
  x = 0
  y = 20
  return x,y # Returns a Tuple containing both x and y

>>> foo()
(0, 20)
51
Justin Ethier

Das Komma in Parameterlisten dient nur zur Trennung der Parameter und ist nicht mit dem Kommaoperator identisch. Der Kommaoperator wertet wie in Ihrem Beispiel sowohl x als auch y aus und wirft dann x weg.

In diesem Fall würde ich vermuten, dass es ein Fehler von jemandem ist, der versucht, zwei Werte zurückzugeben und nicht wusste, wie er dies tun soll.

Dies beantwortet die ursprüngliche Frage zwar nicht wirklich, könnte aber für einige Leute von Interesse sein, aber wenn Sie beide in C++ zurückgeben möchten, müssen Sie sie so schreiben (und einen C++ - 0x-Compiler benötigen.) )

Tuple<int, int> foo()
{
    int x = 0;
    int y = 20;
    return make_Tuple(x, y);
}

Der Zugriff darauf wie folgt -

Tuple<int, int> data = foo();
int a = get<0>(data);
int b = get<1>(data);
9
jcoder
 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

8
kennytm

So wie jeder, der hier kommentiert, denkt, es sei sinnlos und ich stimme dem nicht zu, wenn ich nur das Beispiel anschaue, werde ich eine Vermutung anstellen, die nicht viel besser ist:

Der Autor erhielt eine Compiler-Warnung, dass x nicht in der Funktion verwendet wurde, und dies war eine einfache Möglichkeit, die Warnung zu entfernen.

5
Joel Rondeau

Diese Syntax kann verwendet werden, um zusätzliche Gültigkeitsbereiche in einer if-Anweisung zu speichern. Z.B. normalerweise würden Sie folgendes schreiben:

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

Dies kann durch Folgendes ersetzt werden:

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

Ich denke, dass die Verwendung dieses Codierungsstils eher durch den Drang nach Posieren motiviert wird als durch das Schreiben von sauberem Code.

4
florg

Dies ist der Kommaoperator (,) .

Beide Ausdrücke x und y werden ausgewertet. Das Ergebnis des Gesamtausdrucks ist y, d. H. Der letztere Wert.

Es ist schwer zu sagen, warum es hier verwendet wird. Ich denke mal, zu Demonstrationszwecken. Natürlich kann die Funktion folgendermaßen überarbeitet werden:

int foo()
{
  return 20;
}
4
Daniel Daranas

Das sieht nach einem schrecklichen Beispiel für Code aus. Es könnte eine gültige Syntax in C/C++ sein, aber mir fällt kein Grund ein, warum Sie dies jemals tun möchten.

Wenn Sie sowohl x als auch y zurückgeben möchten, können Sie in C++ besser eine "Point" -Klasse oder -Struktur mit den Eigenschaften x und y definieren und diese zurückgeben. Eine andere Option wäre, x und y als Referenz zu übergeben und dann die Werte in der Methode entsprechend festzulegen.

Wenn die Methode nur y zurückgibt, würde ich einfach y zurückgeben. Wenn x vor der return-Anweisung "ausgewertet" werden muss, sollte dies in einer separaten Zeile erfolgen.

3
Andy White

Es gibt keinen Sinn in dieser return-Anweisung.

Wenn x als volatile deklariert würde, würde dies einen Zugriff erzwingen (da zumindest in C++ Verweise auf volatile-Variablen als extern beobachtbares Verhalten betrachtet werden), dies ist jedoch nicht der Fall.

Wenn anstelle von x eine Art Berechnung mit Nebenwirkungen vorlag, würde dies diese Berechnung durchführen und dann y zurückgeben. Eine nicht-volatilex hat jedoch keine Nebenwirkungen. Die Implementierung ist nicht erforderlich, um Code auszuführen, der keine Nebenwirkungen oder ein von außen beobachtbares Verhalten aufweist. Der Kommaoperator führt alles aus, was sich auf der linken Seite des Kommas befindet, ignoriert das Ergebnis und führt den Wert der rechten Seite aus (und behält den Wert der rechten Seite bei (außer dass es in diesem Fall möglich ist, die linke Seite des Operators zu ignorieren).

Daher ist die return x, y;-Anweisung genau dasselbe wie return y;. Wenn x nicht nur eine völlig sinnlose Sache wäre, wäre es stilistisch besser, es als x; return y; zu schreiben, was genau das Gleiche ist. Es wäre nicht annähernd so verwirrend.

2
David Thornley

Außerhalb von for-Schleifen befindet sich der andere Hauptbenutzer dieses Comman-Operators (wie der Funktionsaufrufversion zugeordnet) in Makros, die nach einigen Vorgängen einen Wert zurückgeben. Dies sind andere Möglichkeiten, dies jetzt zu tun, aber ich denke, dass der Comman-Operator der sauberste Weg war.

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

Bitte beachten Sie, dass dieses Makro im Allgemeinen ein schlechtes Beispiel für Makros ist, da es x und wahrscheinlich aus anderen Gründen wiederholt. Die Verwendung des Kommaoperators auf diese Weise sollte selten sein. Bei dem Beispiel aus Ihrem Buch handelt es sich wahrscheinlich um einen Versuch, einen Code-Ausdruck in die für dieses Beispiel verfügbare Zeilenanzahl zu bringen.

1
nategoose

Dies ist der Komma-Operator. Mit dieser Syntax kann die Warnung des Compilers über die nicht verwendete Variable x deaktiviert werden.

1
osgx

Einerseits könnte es ein ehrlicher Fehler des Schriftstellers sein.

Auf der anderen Seite erklärt der Writer möglicherweise syntaktisch korrekten korrekten Code im Vergleich zu Compiler-Warnungen.

In beiden Fällen besteht die einzige Möglichkeit, mehrere Ergebnisse zurückzugeben, darin, eine Klasse zu definieren und ihre Instanz oder ein Array oder eine Sammlung zu verwenden.

1
Olaseni

Gibt es einen Fall, in dem eine return-Anweisung so erstellt werden muss? 

IMO, ich würde niemals mehrere Rückgaben in einer Funktion wie dem Buchbeispiel verwenden. Es verstößt gegen strukturiertes Design. Trotzdem gibt es viele Programmierer, die das tun! Debuggen des Codes eines anderen Ich habe einer globalen Variablen in jeder return-Anweisung einen Wert zugewiesen, damit ich herausfinden kann, welche return ausgeführt wird.

0
d hughes

Ich habe diese Syntax in C für Housekeeping gesehen, wenn sie mitten in einer Operation zurückkehrt. Definitiv nicht wartbarer Code:

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;

}
0
SRC

Wenn y immer zurückgegeben wird, was ist dann der Punkt? 

Der Punkt ist die Nebenwirkung von x (dh der linken Seite des Kommaoperators). Siehe z.B. Justin Ethier antwortet für Details.

Gibt es einen Fall, in dem eine return-Anweisung so erstellt werden muss? 

Ein Beispiel ist für eine constexpr-Funktion in C++ 11 bis C++ 14: Eine solche Funktion darf keine beliebigen Anweisungen enthalten, sondern genau eine return-Anweisung.

Hier ist ein Codebeispiel von Patrice Roys "Die Ausnahmesituation" auf der CppCon 2016 :

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

Das Buch versucht mögliche Verwirrung von Menschen zu beseitigen, die vor C++ andere Sprachen gelernt haben. In vielen Sprachen können Sie mehrere Werte mit ähnlicher Syntax zurückgeben. In C++ wird es ohne Warnung kompiliert (es sei denn, Sie geben -Wall oder -Wunused-value an), funktioniert jedoch nicht wie erwartet, wenn Sie sich an diese anderen Sprachen gewöhnt haben. Es wird nur der letzte Wert zurückgegeben.

Es scheint jedoch, dass der Autor mehr Verwirrung verursacht hat, als er verhindert hat, da es keine verständliche Situation gibt, eine solche Syntax in einer return-Anweisung in C++ zu verwenden, es sei denn, sie wurde versehentlich wie eine andere Sprache verwendet. Er warnt vor dem Gebrauch, den die meisten Leute nicht bemerken würden. Andernfalls wäre das Debuggen sehr verwirrend, da die Mehrfachzuweisungsanweisung int x, y = foo() ebenfalls gut kompiliert wird.

Fazit: Verwenden Sie immer -Wall und beheben Sie die Warnungen. Mit der C++ - Syntax können Sie viele Dinge schreiben, die keinen Sinn ergeben.

0
Karl Bielefeldt

In Verbindung mit dem Schlüsselwort return gibt der Kommaoperator den Wert " last " zurück. Dieser ist anfangs verwirrend , kann aber die Dinge prägnanter machen .

Das folgende Programm wird beispielsweise mit dem Statuscode 2 beendet.

#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;
}

Beim Kompilieren und Ausführen mit den folgenden Anweisungen sehen Sie die Ausgabe unten. 

michael$ g++ main.cpp -o main.out && ./main.out ; echo $?
one
a
zero
2
0
magnus