Was macht der Kommaoperator ,?

Lesezeit: 8 Minuten

Benutzeravatar von lillq
lillq

Was bedeutet die , Betreiber tun in C?

  • mögliches Duplikat von Was ist die richtige Verwendung des Kommaoperators?

    – Sergej K.

    28. August 2013 um 8:00 Uhr

  • Wie ich in meiner Antwort feststelle, gibt es nach der Auswertung des linken Operanden einen Sequenzpunkt. Dies ist anders als das Komma in einem Funktionsaufruf, das nur grammatikalisch ist.

    – Shafik Yaghmour

    25. Juni 2014 um 11:46 Uhr


  • @SergeyK. — Da diese Frage Jahre vor der anderen gestellt und beantwortet wurde, ist es wahrscheinlicher, dass die andere ein Duplikat dieser Frage ist. Der andere ist jedoch auch mit c und c++ doppelt getaggt, was ein Ärgernis ist. Dies ist ein C-only Q&A mit anständigen Antworten.

    – Jonathan Leffler

    18. Mai 2019 um 0:18 Uhr

Benutzeravatar von lillq
lillq

Der Ausdruck:

(expression1,  expression2)

Zuerst expression1 wird dann ausgewertet expression2 ausgewertet wird, und der Wert von expression2 wird für den gesamten Ausdruck zurückgegeben.

  • Wenn ich dann i = (5,4,3,2,1,0) schreibe, sollte es idealerweise 0 zurückgeben, richtig? aber i wird ein Wert von 5 zugewiesen? Können Sie mir bitte helfen zu verstehen, wo ich falsch liege?

    – Jayesh

    13. November 2010 um 6:55 Uhr

  • @James: Der Wert einer Kommaoperation ist immer der Wert des letzten Ausdrucks. Zu keinem Zeitpunkt i die Werte 5, 4, 3, 2 oder 1 haben. Es ist einfach 0. Es ist praktisch nutzlos, es sei denn, die Ausdrücke haben Seiteneffekte.

    – Jeff Mercado

    13. November 2010 um 7:06 Uhr


  • Beachten Sie, dass zwischen der Auswertung der LHS des Kommaausdrucks und der Auswertung der RHS ein vollständiger Sequenzpunkt liegt (siehe Shafik Yaghmours Antwort für ein Zitat aus dem C99-Standard). Dies ist eine wichtige Eigenschaft des Kommaoperators.

    – Jonathan Leffler

    20. Juni 2014 um 20:47 Uhr


  • i = b, c; ist äquivalent zu (i = b), c weil weil Aufgabe = hat Vorrang vor dem Komma-Operator ,. Der Kommaoperator hat von allen den niedrigsten Vorrang.

    – Radfahrer

    2. Februar 2019 um 6:10 Uhr

  • Ich mache mir Sorgen, dass die Klammern in zweierlei Hinsicht irreführend sind: (1) Sie sind nicht notwendig – der Kommaoperator muss nicht von Klammern umgeben sein; und (2) sie könnten mit den Klammern um die Argumentliste eines Funktionsaufrufs verwechselt werden – aber das Komma in der Argumentliste ist nicht der Kommaoperator. Allerdings ist die Reparatur nicht ganz trivial. Vielleicht: In der Aussage: expression1, expression2; Erste expression1 ausgewertet wird, vermutlich wegen seiner Nebeneffekte (zB Aufruf einer Funktion), dann gibt es einen Sequenzpunkt expression2 wird ausgewertet und der Wert zurückgegeben…

    – Jonathan Leffler

    18. Mai 2019 um 0:22 Uhr

Benutzeravatar von crashmstr
crashmstr

Ich habe die meisten in verwendet gesehen while Schleifen:

string s;
while(read_string(s), s.len() > 5)
{
   //do something
}

Es führt die Operation durch und führt dann einen Test basierend auf einer Nebenwirkung durch. Der andere Weg wäre, es so zu machen:

string s;
read_string(s);
while(s.len() > 5)
{
   //do something
   read_string(s);
}

  • Hey, das ist schick! Ich musste oft unorthodoxe Dinge in einer Schleife tun, um dieses Problem zu beheben.

    – Statiksan

    4. September 2009 um 1:47 Uhr

  • Obwohl es wahrscheinlich weniger obskur und lesbarer wäre, wenn Sie so etwas tun würden: while (read_string(s) && s.len() > 5). Offensichtlich würde das nicht funktionieren, wenn read_string hat keinen (oder keinen sinnvollen) Rückgabewert. (Edit: Entschuldigung, habe nicht bemerkt, wie alt dieser Beitrag ist.)

    – jamesdlin

    25. März 2010 um 8:05 Uhr


  • @staticsan Haben Sie keine Angst vor der Verwendung while (1) mit einer break; Aussage im Körper. Der Versuch, den Breakout-Teil des Codes nach oben in den While-Test oder nach unten in den Do-While-Test zu zwingen, ist oft eine Energieverschwendung und macht den Code schwerer verständlich.

    – potrzebie

    27. September 2012 um 6:20 Uhr

  • @jamesdlin … und die Leute lesen es immer noch. Wenn Sie etwas Nützliches zu sagen haben, dann sagen Sie es. Foren haben Probleme mit wiederbelebten Threads, da Threads normalerweise nach dem Datum des letzten Beitrags sortiert werden. StackOverflow hat solche Probleme nicht.

    – Dimitar Slavchev

    29. November 2012 um 13:36 Uhr

  • @potrzebie Ich mag den Komma-Ansatz viel besser als while(1) und break;

    – Michael

    11. März 2016 um 14:19 Uhr

Benutzeravatar von Shafik Yaghmour
Shafik Yaghmur

Das Komma-Operator wird den linken Operanden auswerten, das Ergebnis verwerfen und dann den rechten Operanden auswerten und das wird das Ergebnis sein. Das idiomatisch Die Verwendung, wie im Link angegeben, erfolgt beim Initialisieren der in a verwendeten Variablen for Schleife, und es gibt das folgende Beispiel:

void rev(char *s, size_t len)
{
  char *first;
  for ( first = s, s += len - 1; s >= first; --s)
      /*^^^^^^^^^^^^^^^^^^^^^^^*/ 
      putchar(*s);
}

Ansonsten gibt es nicht viele Großartig Verwendungen der Komma-Operatorobwohl es leicht zu missbrauchen ist, um Code zu generieren, der schwer zu lesen und zu warten ist.

Von dem Entwurf des C99-Standards die Grammatik ist wie folgt:

expression:
  assignment-expression
  expression , assignment-expression

und Absatz 2 sagt:

Das linker Operand eines Komma-Operators wird als void-Ausdruck ausgewertet; es gibt einen Sequenzpunkt nach seiner Auswertung. Dann ist die rechter Operand wird ausgewertet; das Ergebnis hat seinen Typ und Wert. 97) Wenn versucht wird, das Ergebnis eines Kommaoperators zu ändern oder nach dem nächsten Sequenzpunkt darauf zuzugreifen, ist das Verhalten undefiniert.

Fußnote 97 sagt:

Ein Komma-Operator tut es keinen lvalue liefern.

was bedeutet, dass Sie das Ergebnis nicht zuordnen können Komma-Operator.

Es ist wichtig zu beachten, dass der Kommaoperator das hat niedrigste Priorität und daher gibt es Fälle, in denen verwendet wird () kann einen großen Unterschied machen, zum Beispiel:

#include <stdio.h>

int main()
{
    int x, y ;

    x = 1, 2 ;
    y = (3,4) ;

    printf( "%d %d\n", x, y ) ;
}

wird die folgende Ausgabe haben:

1 4

Benutzeravatar von Paul Stephenson
Paul Stephenson

Der Kommaoperator kombiniert die beiden Ausdrücke auf beiden Seiten zu einem und wertet sie beide in der Reihenfolge von links nach rechts aus. Der Wert der rechten Seite wird als Wert des gesamten Ausdrucks zurückgegeben.
(expr1, expr2) ist wie { expr1; expr2; } aber Sie können das Ergebnis von verwenden expr2 in einem Funktionsaufruf oder einer Zuweisung.

Es ist oft in zu sehen for Schleifen zum Initialisieren oder Verwalten mehrerer Variablen wie folgt:

for (low = 0, high = MAXSIZE; low < high; low = newlow, high = newhigh)
{
    /* do something with low and high and put new values
       in newlow and newhigh */
}

Abgesehen davon habe ich es nur in einem anderen Fall “im Zorn” verwendet, als ich zwei Operationen, die immer zusammengehören sollten, in einem Makro zusammenfasste. Wir hatten Code, der verschiedene Binärwerte in einen Byte-Puffer kopierte, um sie über ein Netzwerk zu senden, und einen Zeiger, der dort beibehalten wurde, wo wir angekommen waren:

unsigned char outbuff[BUFFSIZE];
unsigned char *ptr = outbuff;

*ptr++ = first_byte_value;
*ptr++ = second_byte_value;

send_buff(outbuff, (int)(ptr - outbuff));

Wo die Werte waren shorts oder intn wir haben das gemacht:

*((short *)ptr)++ = short_value;
*((int *)ptr)++ = int_value;

Später lesen wir, dass dies kein wirklich gültiges C war, weil (short *)ptr ist kein l-Wert mehr und kann nicht inkrementiert werden, obwohl unser damaliger Compiler nichts dagegen hatte. Um dies zu beheben, teilen wir den Ausdruck in zwei Teile:

*(short *)ptr = short_value;
ptr += sizeof(short);

Dieser Ansatz beruhte jedoch darauf, dass alle Entwickler daran dachten, immer beide Anweisungen einzufügen. Wir wollten eine Funktion, bei der Sie den Ausgabezeiger, den Wert und den Typ des Werts übergeben können. Da dies C ist, nicht C++ mit Vorlagen, konnten wir keine Funktion einen beliebigen Typ annehmen lassen, also haben wir uns für ein Makro entschieden:

#define ASSIGN_INCR(p, val, type)  ((*((type) *)(p) = (val)), (p) += sizeof(type))

Durch die Verwendung des Komma-Operators konnten wir dies in Ausdrücken oder als Anweisungen verwenden, wie wir wollten:

if (need_to_output_short)
    ASSIGN_INCR(ptr, short_value, short);

latest_pos = ASSIGN_INCR(ptr, int_value, int);

send_buff(outbuff, (int)(ASSIGN_INCR(ptr, last_value, int) - outbuff));

Ich schlage nicht vor, dass eines dieser Beispiele guten Stil hat! Tatsächlich erinnere ich mich an Steve McConnells Code abgeschlossen sogar davon abzuraten, Kommaoperatoren in a zu verwenden for Schleife: Aus Gründen der Lesbarkeit und Wartbarkeit sollte die Schleife nur von einer Variablen gesteuert werden, und die Ausdrücke in der for Die Zeile selbst sollte nur Schleifensteuerungscode enthalten, keine anderen zusätzlichen Bits zur Initialisierung oder Schleifenwartung.

Es bewirkt die Auswertung mehrerer Anweisungen, verwendet aber nur die letzte als Ergebniswert (rvalue, glaube ich).

So…

int f() { return 7; }
int g() { return 8; }

int x = (printf("assigning x"), f(), g() );

sollte dazu führen, dass x auf 8 gesetzt wird.

  • Es tut. Und es wird auf 11 gesetzt, wenn Sie die äußeren geschweiften Klammern weglassen. Ziemlich interessant und für einige Fälle definitiv eine Compiler-Warnung wert.

    – Sebkrämer

    12. Oktober 2020 um 10:57 Uhr

Benutzeravatar von DGentry
DGentry

Wie frühere Antworten angegeben haben, werden alle Anweisungen ausgewertet, aber die letzte als Wert des Ausdrucks verwendet. Persönlich fand ich es nur in Schleifenausdrücken nützlich:

for (tmp=0, i = MAX; i > 0; i--)

  • Es tut. Und es wird auf 11 gesetzt, wenn Sie die äußeren geschweiften Klammern weglassen. Ziemlich interessant und für einige Fälle definitiv eine Compiler-Warnung wert.

    – Sebkrämer

    12. Oktober 2020 um 10:57 Uhr

Der einzige Ort, an dem ich gesehen habe, dass es nützlich ist, ist, wenn Sie eine funky Schleife schreiben, in der Sie mehrere Dinge in einem der Ausdrücke tun möchten (wahrscheinlich der Init-Ausdruck oder der Schleifenausdruck. So etwas wie:

bool arraysAreMirrored(int a1[], int a2[], size_t size)
{
  size_t i1, i2;
  for(i1 = 0, i2 = size - 1; i1 < size; i1++, i2--)
  {
    if(a1[i1] != a2[i2])
    {
      return false;
    }
  }

  return true;
}

Verzeihen Sie mir, wenn es irgendwelche Syntaxfehler gibt oder wenn ich irgendetwas eingemischt habe, das nicht strikt C ist. Ich behaupte nicht, dass der Operator , eine gute Form ist, aber dafür könnten Sie ihn verwenden. Im obigen Fall würde ich wahrscheinlich a verwenden while loop stattdessen, damit die mehreren Ausdrücke auf init und loop offensichtlicher wären. (Und ich würde i1 und i2 inline initialisieren, anstatt sie zu deklarieren und dann zu initialisieren … bla bla bla.)

  • Ich nehme an, Sie meinen i1 = 0, i2 = Größe -1

    – Franken

    13. August 2009 um 14:05 Uhr

1425720cookie-checkWas macht der Kommaoperator ,?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy