Question

trouvé ce morceau de code sur Wikipedia.

#include <stdio.h>

int main(void)
{
  int c;

  while (c = getchar(), c != EOF && c != 'x')
  {
    switch (c)
      {
      case '\n':
      case '\r':
        printf ("Newline\n");
        break;
      default:
        printf ("%c",c);
      }
  }
  return 0;
}

Je suis curieux de savoir l'expression utilisée comme condition pour en boucle:

while (c = getchar(), c != EOF && c != 'x')

Il est tout à fait évident ce qu'il fait, mais je ne l'ai jamais vu cette construction avant. Est-ce spécifique à while ? Sinon, comment ne l'analyseur / compilateur de déterminer de quel côté d'expression séparés par des virgules renvoie la valeur booléenne pour en boucle?

Était-ce utile?

La solution

virgule de l'opérateur est un opérateur binaire qui évalue son premier opérande et rejette le résultat, il évalue alors le deuxième opérande et renvoie cette valeur.

Il est également un , ce qui signifie que tous les effets secondaires seront calculés avant la prochaine partie du code est exécuté.

Autres conseils

L'opérateur virgule est un beastie bizarre jusqu'à ce que vous arrivez à le comprendre, et ce n'est pas spécifique à while.

L'expression:

exp1, exp2

évalue exp1 évalue ensuite exp2 et retourne exp2.

Vous le voyez souvent, mais vous ne pouvez pas le réaliser:

for (i = j = 0; i < 100; i++, j += 2)

Vous n'êtes pas réellement avec la valeur de retour de "i++, j += 2" mais il est là quand même. L'opérateur virgule évalue les deux bits à modifier à la fois i et j.

Vous pouvez très bien l'utiliser partout une expression normale peut être utilisé (la virgule dans votre fonction appelle est pas un opérateur virgule, par exemple) et il est très utile dans l'écriture du code source compact, si c'est ce que vous aimez. De cette façon, il fait partie de la famille qui permet à des choses comme:

while ((c= getchar()) != EOF) {...}
i = j = k = 0;

et ainsi de suite.

Pour votre exemple précis:

while (c = getchar(), c != EOF && c != 'x')

le produit suivant:

  • c = getchar() est exécuté entièrement (l'opérateur virgule est un point de la séquence).
  • c != EOF && c != 'x' est exécuté.
  • l'opérateur virgule jette la première valeur (c) et « rendement » de la seconde.
  • la while utilise cette valeur de retour pour contrôler la boucle.

Dans de nombreuses langues, la virgule est un opérateur qui aboutit toujours à la valeur du deuxième opérande. Les opérandes sont évalués de manière séquentielle de gauche à droite.

Pseudo-code:

a = 10
print a = 7 + 8, a * 2

Note:. print est considéré comme une déclaration qui ne prend pas d'arguments, donc ce qui vient après est considéré comme le a = 7 + 8, a * 2 d'expression unique

Exécuté comme ceci:

  • Première ligne
    • mettre 10 dans a
  • Deuxième ligne
    • évaluer 7 + 8 (15)
    • placer une valeur évaluée (de 15) dans a
    • évaluer a * 2 (30)
    • évaluer opérateur , avec opérandes 15 et 30:
      • toujours la valeur de deuxième opérande (30)
    • print valeur évaluée (30)

Pour développer un peu sur les autres réponses, dans ce code:

EXPRESSION_1 , EXPRESSION_2

EXPRESSION_1 est d'abord évaluée, alors il y a un point de la séquence, puis expression_2 est évaluée, et la valeur de l'ensemble est la valeur de expression_2.

L'ordre de la garantie de fonctionnement et le point de séquence sont importantes pour le code que vous avez cité. Ensemble, ils veulent dire que nous pouvons être certains que la fonction getchar () est appelée et la valeur de la variable c est entièrement mis à jour avant que la valeur de c est testé.

virgule est un opérateur. Elle renvoie la valeur de l'expression de la main droite par défaut . L'ordre d'évaluation est garantie à gauche d'abord, puis à droite.

Mise à jour (réponse au commentaire de Pax):

Tout comme la plupart des opérateurs, il peut être surchargé pour les types définis par l'utilisateur:

#include <iostream>
#include <string>
using namespace std;

enum EntryType { Home, Cell, Address };

class AddressBookEntryReference {
public:
    AddressBookEntryReference(const string& name, const EntryType &entry)
        : Name(name), Entry(entry) { }
    string Name;
    EntryType Entry;
};

AddressBookEntryReference operator,(const string& name, const EntryType &type) {
    return AddressBookEntryReference(name, type);
}

class AddressBook {
    string test;
public:
    string& operator[](const AddressBookEntryReference item) {
        // return something based on item.Name and item.Entry.

        // just to test:
        test = item.Name;
        return test;
    }
};

int main() {
    // demo:
    AddressBook book;
    cout << book["Name", Cell]  // cool syntax! 
         << endl;
}
scroll top