2013-05-15 13 views
18

Właśnie natknąć się kod, który zasadniczo wykonuje następujące operacje:Co oznacza lista wartości oddzielonych przecinkami, ujęta w nawias w C? a = (1, 2, 3);

int a = (1, 2, 3); 

Nigdy nie widziałem tej notacji wcześniej. Co to znaczy?

+12

marnowanie wpisanego kodu, który jest. 3 jest przypisane do a. –

+0

Zastanawiam się jednak, kiedy ktoś wykopuje dla tego duplikat (ponieważ nie mogę uwierzyć, że nie ma żadnego). –

+1

@ ChristianRau, jest bardzo prawdopodobne, że istnieje - ale ja naprawdę walczyłem o skonstruowanie zapytania w google i StackOverflow, które zwróciło znaczące wyniki, ponieważ nie znam nazwy operatora! –

Odpowiedz

36

to comma operator: ocena a, b najpierw podlega ocenie a, następnie b, a wynikiem jest b.

int a = (1, 2, 3); ocenia najpierw 1, następnie 2 wreszcie 3 i wykorzystuje ten ostatni 3 do zainicjowania a. Jest to bezużyteczne, ale może być użyteczne, gdy lewy operand z , ma efekty uboczne (zwykle: gdy jest to wywołanie funkcji).

+0

Zazwyczaj piszę to jak '({doSomething(); x;})', co jest szczególnie przydatne w przypadku definicji makr, które działają z tymczasowymi rezultatami. Czy istnieje jakaś różnica między tymi oznaczeniami, poza faktem, że używam średnika zamiast przecinka, aby oddzielić te (pod) wyrażenia? – leemes

+2

@leemes Jest to nieważne w standardowym C i C++, ale jest akceptowane przez niektóre kompilatory (przynajmniej GCC) jako rozszerzenie pozwalające na używanie instrukcji, a nie tylko na wyrażenia, dzięki czemu możesz zrobić '({if (0) {1;} 2;}) '. – hvd

+0

"zwykle: kiedy jest to wywołanie funkcji" czy możesz to wyjaśnić? Pytam, ponieważ nie rozumiem kontekstu. masz na myśli foo (T, T2), ten przecinek lub foo (T), foo (T)? –

19

Wykorzystuje comma operator, który to ocenia każdą kolejno ekspresji operandu (wprowadzenie właściwej sekwencji wskazuje pomiędzy nimi) i zwraca ostatni. Zatem twój przykład jest faktycznie równoważny z int a = 3;.

Ale to jest rzeczywiście jednym z najmniej wykorzystywanych operatorów C i C++ i nie należy mylić z przecinkami wyrażeń użytych w wywołaniu funkcji list inicjująca i wszystkich innych miejscach. Niezbyt rzadkim przypadkiem użycia byłoby wielokrotne zwiększenie liczby pętli (for(...; ...; ++i,++j)), mimo że prawdopodobnie nigdy nie myślałeś o tym używając tak zwanego operatora przecinka.

Kolejny problem polegający na interwencji jest próbą umieszczenia wielu konceptualnie powiązanych wyrażeń w pojedynczym komunikacie (np. Zwrot) ze względu na jasność i zwięzłość, tak jak w przypadku implementacji starego dobrego frexp z argumentem zwracającym dziwny wskaźnik (ignorować faktu, że właściwa C++ po prostu wrócić parę):

double frexp(double arg, int *exp) 
{ 
    if(...) 
     return *exp=..., result; 
    ... 
} 

który jest o wiele bardziej efektywna niż równowartość

double frexp(double arg, int *exp) 
{ 
    if(...) 
    { 
     *exp = ...; 
     return result; 
    } 
    ... 
} 
+4

Podoba mi się ta odpowiedź lepiej niż obecnie najlepiej głosowana przez hvd, ale kim jestem, aby dyskutować z Internetem? ':)' –

+1

@ ChristianRau zapamiętaj [to] (http://stackoverflow.com/questions/16538458/how-to-make-ix-works-as-i/16538741#16538741), możesz to zrobić, używając przecinka tutaj i pokaż przykład :-) –

+0

@Koushik Hah, racja! Nadal dziwne, ale lepsze od wersji '?:'. Wciąż jednak nie pokażę tego w tej odpowiedzi, ponieważ tak naprawdę nie jest to rozsądny przypadek użycia. Ale +1 dla wzajemnego powiązania. –

3

Wylicza tylko 1, 2 i 3 (ponieważ są to tylko wartości, ale równie dobrze mogą być wywołania funkcji) i ustawia wartość (lub wartość zwracaną) ostatniej wartości na lewy operand (w twoim przykładzie, za).

Może to pomoże Ci zrozumieć, jak to działa:

#include <stdio.h> 

int toto() 
{ 
    printf("toto()\n"); 
    return (21); 
} 

int tata() 
{ 
    printf("tata()\n"); 
    return (42); 
} 

int main() 
{ 
    int a = (toto(), tata()); 
    printf("%d\n", a); 
    return (0); 
} 

wyjściowa:

toto() 
tata() 
42 

Edit: kod THA C, działa tak samo w C++

+0

Wziąłem wolność, aby dodać odpowiednie wyjście. –

5

Jest operator przecinek . Standard C11 mówi o jednym przypadku użycia tego rodzaju operatora.

C11 standard 6: 5: 17

przecinek operatora

Lewa argumentu operatora przecinek oceniano jako pusta ekspresji; istnieje punkt sekwencji między jego oceną a tym prawego argumentu. Następnie prawy operand jest oceniany; wynik ma swój typ i value.114)

Operator przecinka (w sposób opisany w niniejszym podrozdziale ) nie może pojawić się w kontekstach, gdzie przecinek jest używany do odrębne pozycje na liście (na przykład jako argumenty funkcji lub list z inicjalizatorów ). Z drugiej strony, może być stosowany w nawiasach w postaci lub w drugim wyrażeniu operatora warunkowego w takich kontekstach. W wywołaniu funkcji f (a, (t = 3, t + 2), c), funkcja posiada trzy parametry, z których druga ma wartość 5.

3

To comma operator . "Owija" wiele wyrażeń, ocenia je od lewej do prawej, a wartość całego wyrażenia jest określana przez ostatnie podekspresję. W twoim przykładzie wartość ta wynosi 3.

Sytuacja, w której szczególnie przydatny jest operator przecinka, polega na tym, że chcesz wykonać wiele czynności w wyrażeniu "inkrementacja" pętli for, na przykład aby zwiększyć dwóch zmiennych.

Przykład: Iteracja obrazu wzdłuż przekątnej, przy użyciu x i y jako oddzielnych zmiennych. Używam dwóch oddzielnych zmiennych dla x i y, ponieważ mógłbym zmienić jeden z nich w pętli niezależnie od drugiego (pamiętaj, to tylko głupi przykład). Więc chcę, aby zwiększyć zarówno x i y w „przyrost” Oświadczenie dla pętli:

for(int x = 0, y = 0; x < width && y < height; ++x, ++y) { 
    // ...          ^^^^^^^^ 
} 

Zauważ, że „inicjalizacji” wyrazem dla pętli robi nie użyć operatora przecinek; to po prostu deklaruje dwie zmienne.

+1

Wolałbym zmienić * "separator" * na * "operator" * w pierwszym zdaniu, ponieważ ten pierwszy byłby raczej tym, co nazywam zwykłym (bez operatora) użyciem przecinków. Ale dobrze, że wskazałeś różnicę do wyrażenia inicjalizacji pętli for. –

+0

Ups, to było przez przypadek. Dzięki za wskazanie;) – leemes

Powiązane problemy