programowanieProgramista C, programista systemowy

Wyjaśnij, jak działa operator przecinka (comma operator) w języku C. Kiedy ma sens jego użycie, z jakimi błędami często spotykają się programiści przy jego zastosowaniu i jakie są nieoczekiwane efekty?

Zdaj rozmowy kwalifikacyjne z asystentem AI Hintsage

Odpowiedź

Operator przecinka , w języku C łączy dwa (lub więcej) wyrażeń, obliczając je po kolei z lewej na prawą i zwracając wartość ostatniego wyrażenia:

int x = (f(), g()); // wywoływane są f() i g(), x == wynik g()

Najczęściej używany w pętlach for:

for(int i = 0, j = 10; i < j; ++i, --j) { ... }

Kiedy przydatne:

  • Gdy potrzebujesz krótko zapisać kilka wyrażeń, szczególnie w inicjalizacji lub inkrementacji.

Pułapki:

  • Priorytet przecinka jest bardzo niski, co jest istotne przy złożonych wyrażeniach;
  • Użycie poza kontekstem (na przykład w return lub przypisaniu) może prowadzić do nieoczekiwanych wyników;
  • Użycie bez nawiasów może zmylić programistę i kompilator.

Pytanie z podstępem

Pytanie: Co wydrukuje poniższy kod?

int a = 1; int b = (a = 2, a + 3); printf("%d ", b);

Odpowiedź: Wydrukuje "5". Najpierw przypisywana jest a=2, po czym wyrażenie a+3 oblicza 2+3=5, i to właśnie wartość będzie przypisana zmiennej b.


Przykłady rzeczywistych błędów


Historia

W projekcie w języku C programista użył operatora przecinka bez nawiasów w funkcji zwracającej:

return x++, y++;

Oczekiwano, że funkcja zwróci y+1, ale faktycznie return bierze pod uwagę tylko wynik wyrażenia po prawej, a po lewej x++ jest obliczane osobno. To zmyliło kod użytkownika, ponieważ wynik return okazał się inny, niż zamierzano.


Historia

W jednej pętli for programista przypadkowo umieścił przecinek zamiast średnika:

for(i=0, i<10, i++) ...

Program skompilował się, ale pętla wykonała się tylko raz, ponieważ wyrażenie i<10, i++ w warunkach for zawsze zwraca wynik ostatniego wyrażenia (i++), a nie warunek kontynuacji pętli.


Historia

Podczas pisania makr jeden z programistów zdefiniował:

#define DO(x, y) x, y int v = DO(f(), g());

Oczekiwał, że obie funkcje zostaną wywołane, ale zapomniał o nawiasach. W rezultacie wywołano tylko f(); wartość g() nie została przypisana do v. Prawidłowe użycie: #define DO(x, y) ((x), (y)).