Frage

Was bedeutet das , Operator in C tun?

War es hilfreich?

Lösung

Der Ausdruck:

(expression1,  expression2)

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

Andere Tipps

Ich habe es am häufigsten in gesehen while Schleifen:

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

Es wird die Operation durchführen und dann einen Test basierend auf einer Nebenwirkung durchführen.Die andere Möglichkeit wäre, es so zu machen:

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

Der Komma-Operator wertet den linken Operanden aus, verwirft das Ergebnis und wertet dann den rechten Operanden aus, und das ist das Ergebnis.Der idiomatisch Die im Link angegebene Verwendung erfolgt bei der Initialisierung 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-Operator, obwohl es so ist leicht zu missbrauchen 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:

Der Der linke Operand eines Kommaoperators wird als ungültiger Ausdruck ausgewertet. Nach seiner Auswertung gibt es einen Sequenzpunkt.Dann ist die rechter Operand wird ausgewertet;Das Ergebnis hat seine Art und seinen 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 Kommaoperator tut dies ergibt keinen L-Wert.

was bedeutet, dass man das Ergebnis nicht zuordnen kann Komma-Operator.

Es ist wichtig zu beachten, dass der Kommaoperator das hat niedrigster Vorrang und deshalb 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

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.

Man sieht es oft in 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 zusammenfasste, die in einem Makro immer zusammenpassen sollten.Wir hatten Code, der verschiedene Binärwerte in einen Bytepuffer kopierte, um sie über ein Netzwerk zu senden, und einen Zeiger, der dort blieb, 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 ints haben wir das gemacht:

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

Später lesen wir, dass dies kein wirklich gültiges C sei, weil (short *)ptr ist kein L-Wert mehr und kann nicht erhöht werden, obwohl es unserem damaligen Compiler nichts ausmachte.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 stets daran dachten, beide Anweisungen einzugeben.Wir wollten eine Funktion, bei der Sie den Ausgabezeiger, den Wert und den Typ des Werts übergeben können.Da es sich um C und nicht um C++ mit Vorlagen handelt, konnten wir einer Funktion keinen beliebigen Typ annehmen, 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 nach Belieben in Ausdrücken oder als Anweisungen verwenden:

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 behaupte nicht, dass eines dieser Beispiele guten Stil hat!Tatsächlich scheine ich mich an die von Steve McConnell zu erinnern Code abgeschlossen Es wird davon abgeraten, 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 jedoch nur die letzte als resultierenden Wert (r-Wert, glaube ich).

Also...

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.

Der Komma-Operator macht nichts Sinnvolles, es ist eine 100 % überflüssige Funktion.Der Hauptzweck besteht darin, dass „Leute versuchen, schlau zu sein“ und es daher verwenden, um (unbeabsichtigt) lesbaren Code zu verschleiern.Der Haupteinsatzbereich ist die Verschleierung von for-Schleifen, zum Beispiel:

for(int i=0, count=0; i<x; i++, count++)

Wo int i=0, count=0 ist eigentlich kein Kommaoperator, sondern eine Deklarationsliste (wir sind hier schon verwirrt). i++, count++ ist der Kommaoperator, der zuerst den linken Operanden und dann den rechten Operanden auswertet.Das Ergebnis des Kommaoperators ist das Ergebnis des rechten Operanden.Das Ergebnis des linken Operanden wird verworfen.

Aber der obige Code könnte ohne den Komma-Operator viel besser lesbar geschrieben werden:

int count = 0;
for(int i=0; i<x; i++) // readable for loop, no nonsense anywhere
{
  ...
  count++;
}

Die einzige wirkliche Verwendung des Komma-Operators, die ich gesehen habe, sind künstliche Diskussionen über Sequenzpunkte, da der Komma-Operator einen Sequenzpunkt zwischen der Auswertung des linken und rechten Operanden enthält.

Wenn Sie also einen undefinierten Verhaltenscode wie diesen haben:

printf("%d %d", i++, i++);

Sie können es tatsächlich durch Schreiben in ein lediglich nicht spezifiziertes Verhalten (Reihenfolge der Auswertung von Funktionsparametern) umwandeln

printf("%d %d", (0,i++), (0,i++));

Zwischen jeder Auswertung von gibt es nun einen Sequenzpunkt i++, damit das Programm zumindest nicht mehr abstürzt und brennt, auch wenn die Reihenfolge der Auswertung der Funktionsparameter nicht festgelegt ist.

Natürlich würde niemand solchen Code in echten Anwendungen schreiben, er ist nur für Diskussionen von Sprachjuristen über Sequenzpunkte in der Sprache C nützlich.

Der Kommaoperator ist von MISRA-C:2004 und MISRA-C:2012 mit der Begründung verboten, dass er weniger lesbaren Code erzeugt.

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

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

Der einzige Ort, an dem ich gesehen habe, dass es nützlich ist, ist, wenn Sie eine unkonventionelle Schleife schreiben, in der Sie mehrere Dinge in einem der Ausdrücke tun möchten (wahrscheinlich dem Init-Ausdruck oder dem Schleifenausdruck).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;
}

Entschuldigen Sie, wenn es Syntaxfehler gibt oder ich etwas eingemischt habe, das nicht strikt C ist.Ich behaupte nicht, dass der ,-Operator eine gute Form ist, aber dafür könnte man ihn verwenden.Im obigen Fall würde ich wahrscheinlich a verwenden while stattdessen eine Schleife verwenden, damit die mehreren Ausdrücke in 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 greife dies einfach wieder auf, um Fragen von @Rajesh und @JeffMercado zu beantworten, die meiner Meinung nach sehr wichtig sind, da dies einer der Top-Suchmaschinenhits ist.

Nehmen Sie zum Beispiel den folgenden Codeausschnitt

int i = (5,4,3,2,1);
int j;
j = 5,4,3,2,1;
printf("%d %d\n", i , j);

Es wird gedruckt

1 5

Der i Der Fall wird wie in den meisten Antworten erläutert behandelt.Alle Ausdrücke werden in der Reihenfolge von links nach rechts ausgewertet, aber nur der letzte wird zugewiesen i.Das Ergebnis der ( Ausdruck )is1`.

Der j Der Fall unterliegt seitdem unterschiedlichen Vorrangregeln , hat die niedrigste Operatorpriorität.Aufgrund dieser Regeln sieht der Compiler Zuweisungsausdruck, Konstante, Konstante ....Die Ausdrücke werden erneut in der Reihenfolge von links nach rechts ausgewertet und ihre Nebenwirkungen bleiben sichtbar. j Ist 5 als Ergebnis j = 5.

Interessanterweise, int j = 5,4,3,2,1; ist laut Sprachspezifikation nicht zulässig.Ein Initialisierer erwartet eine Zuweisungsausdruck also eine direkte , Betreiber ist nicht zulässig.

Hoffe das hilft.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top