Do czego służy operator przecinka?
Co robi operator ,
W C?
8 answers
Wyrażenie:
(expression1, expression2)
Najpierw zostanie obliczone wyrażenie1, następnie zostanie obliczone wyrażenie2 i zostanie zwrócona wartość wyrażenie2 dla całego wyrażenia.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-09 18:37:07
Widziałem najczęściej używane w while
pętle:
string s;
while(read_string(s), s.len() > 5)
{
//do something
}
Wykona operację, a następnie zrobi test na podstawie efektu ubocznego. Innym sposobem byłoby zrobić to tak:
string s;
read_string(s);
while(s.len() > 5)
{
//do something
read_string(s);
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-01-29 05:13:13
Operator przecinka łączy dwa wyrażenia po obu jego stronach w jedno, oceniając je w kolejności od lewej do prawej. Wartość prawej strony jest zwracana jako wartość całego wyrażenia.
(expr1, expr2)
jest podobne do { expr1; expr2; }
, ale możesz użyć wyniku expr2
w wywołaniu funkcji lub przypisaniu.
W pętlach for
często widzi się inicjalizację lub utrzymywanie wielu zmiennych, takich jak:
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 */
}
Poza tym, użyłem go tylko "w Gniewie" w jednym innym przypadku, gdy podsumowując dwie operacje, które powinny zawsze iść razem w makro. Mieliśmy kod, który kopiował różne wartości binarne do bufora bajtowego do wysyłania w sieci, i wskaźnik utrzymywany tam, gdzie doszliśmy do:
unsigned char outbuff[BUFFSIZE];
unsigned char *ptr = outbuff;
*ptr++ = first_byte_value;
*ptr++ = second_byte_value;
send_buff(outbuff, (int)(ptr - outbuff));
Gdzie wartości były short
S lub int
S zrobiliśmy to:
*((short *)ptr)++ = short_value;
*((int *)ptr)++ = int_value;
Później czytamy, że to nie było tak naprawdę poprawne C, ponieważ (short *)ptr
nie jest już wartością l i nie może być zwiększana, chociaż nasz kompilator w tym czasie nie miał nic przeciwko. Aby to naprawić, dzielimy wyrażenie w dwóch:
*(short *)ptr = short_value;
ptr += sizeof(short);
Jednak to podejście polegało na tym, że wszyscy deweloperzy pamiętali o umieszczaniu obu deklaracji przez cały czas. Chcieliśmy funkcji, gdzie można przekazać w wskaźniku wyjściowym, wartość i typ wartości. To jest C, a nie c++ z szablonami, nie mogliśmy mieć funkcji przyjmującej dowolny typ, więc zdecydowaliśmy się na Makro:
#define ASSIGN_INCR(p, val, type) ((*((type) *)(p) = (val)), (p) += sizeof(type))
Używając operatora przecinka mogliśmy użyć tego w wyrażeniach lub jako instrukcji :
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));
Nie sugeruję, że któryś z tych przykładów to dobry styl! W rzeczy samej, wydaje mi się, że pamiętam kompletny kod Steve ' a McConnella zalecający nawet używanie operatorów przecinkowych w pętli for
: dla czytelności i utrzymania pętli, pętla powinna być kontrolowana tylko przez jedną zmienną, a wyrażenia w samej linii for
powinny zawierać tylko kod kontrolujący pętlę, a nie inne dodatkowe bity inicjalizacji lub utrzymania pętli.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-10-15 19:32:41
Operator przecinka oceni lewy operand, odrzuci wynik, a następnie oceni prawy operand i będzie to wynik. Idiomatic jest używany, jak zaznaczono w linku, podczas inicjalizacji zmiennych używanych w pętli for
i daje następujący przykład:
void rev(char *s, size_t len)
{
char *first;
for ( first = s, s += len - 1; s >= first; --s)
/*^^^^^^^^^^^^^^^^^^^^^^^*/
putchar(*s);
}
W Przeciwnym Razie nie ma wielu wspaniałych zastosowańoperatora przecinka , chociaż łatwo jest nadużywać generować kod, który jest trudny do odczytania i utrzymać.
Z projektu standardu C99 gramatyka jest następująca:
expression:
assignment-expression
expression , assignment-expression
I paragraf 2 mówi:
Lewy operand operatora przecinka jest oceniany jako puste wyrażenie; {[31] } po jego ocenie znajduje się punkt sekwencji. Następnie jest obliczany parametr right; wynik ma swój typ i wartość. 97) jeśli zostanie podjęta próba modyfikacji wyniku operatora przecinka lub uzyskania do niego dostępu po następnej sekwencji punkt, zachowanie jest nieokreślone.
przypis 97 mówi:
Operator przecinka nie daje lvalue .
Co oznacza, że nie można przypisać do wyniku operatora przecinka.
Ważne jest, aby pamiętać, że operator przecinka ma najniższy priorytet i dlatego istnieją przypadki, w których użycie ()
może zrobić dużą różnicę, na przykład:
#include <stdio.h>
int main()
{
int x, y ;
x = 1, 2 ;
y = (3,4) ;
printf( "%d %d\n", x, y ) ;
}
Będzie miał następujące wyjście:
1 4
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:10:41
Powoduje ewaluację wielu poleceń, ale używa tylko ostatniego jako wartości wynikowej (rvalue, jak sądzę).
Więc...int f() { return 7; }
int g() { return 8; }
int x = (printf("assigning x"), f(), g() );
Powinno spowodować, że x zostanie ustawione na 8.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-09 18:37:35
Operator przecinka nie robi nic sensownego, jest to w 100% zbędna funkcja. Głównym jego zastosowaniem jest "ludzie próbują być mądrzy" i dlatego używają go do (nieumyślnie) zaciemniania czytelnego kodu. Głównym obszarem zastosowania jest zaciemnianie pętli, na przykład:
for(int i=0, count=0; i<x; i++, count++)
Gdzie int i=0, count=0
w rzeczywistości nie jest operatorem przecinka, ale listą deklaracji(już tu jesteśmy zdezorientowani). {[5] } jest operatorem przecinka, który ocenia najpierw lewy, a następnie prawy. Wynik operator przecinka jest wynikiem właściwego operandu. Wynik lewego operandu jest odrzucany.
Ale powyższy kod mógłby być napisany w znacznie bardziej czytelny sposób bez operatora przecinka:
int count = 0;
for(int i=0; i<x; i++) // readable for loop, no nonsense anywhere
{
...
count++;
}
Jedynym prawdziwym zastosowaniem operatora przecinka, jakie widziałem, są sztuczne dyskusje na temat punktów sekwencji, ponieważ operator przecinka zawiera punkt sekwencji między oceną lewego i prawego operandu.
Więc jeśli masz jakiś niezdefiniowany kod zachowania jak to:
printf("%d %d", i++, i++);
W rzeczywistości można przekształcić to w tylko nieokreślone zachowanie (kolejność oceny parametrów funkcji), pisząc
printf("%d %d", (0,i++), (0,i++));
Pomiędzy każdą ewaluacją i++
jest teraz punkt sekwencji, więc przynajmniej program nie będzie ryzykował awarii i spalenia się dłużej, nawet jeśli kolejność ewaluacji parametrów funkcji pozostaje nieokreślona.
Oczywiście nikt nie napisze takiego kodu w rzeczywistych aplikacjach, jest on przydatny tylko w dyskusjach językowych o punkty sekwencji w języku C.
Operator przecinka jest zakazany przez MISRA-C:2004 i MISRA-c:2012 z uzasadnieniem, że tworzy mniej czytelny kod.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-03-24 16:26:59
Jak stwierdzono we wcześniejszych odpowiedziach, ewaluuje wszystkie polecenia, ale używa ostatniego jako wartości wyrażenia. Osobiście uważam, że jest to przydatne tylko w wyrażeniach pętlowych:
for (tmp=0, i = MAX; i > 0; i--)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-09 18:43:30
Jedyne miejsce, gdzie widziałem, że jest to przydatne jest, gdy piszesz funky pętli, gdzie chcesz zrobić wiele rzeczy w jednym z wyrażeń (prawdopodobnie wyrażenie init lub wyrażenie pętli. Coś w stylu:
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;
}
Przepraszam, jeśli są jakieś błędy składniowe lub jeśli zmieszałem coś, co nie jest ścisłe C. Nie twierdzę, że operator , jest dobrą formą, ale do tego można go użyć. W powyższym przypadku prawdopodobnie użyłbym pętli while
, więc wiele wyrażeń na init i pętla byłaby bardziej oczywista. (I inicjalizowałbym i1 I i2 inline zamiast deklarować, a następnie inicjować.... bla bla bla.)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-09-04 01:27:03