Описано, как не надо применять операцию "запятая" в Си.(читать дальше)Придётся смириться: в языке Си есть запятая. Запятая есть двух видов -- разделительная и "операция запятая".
Разделительная запятая применяется:
1. При перечислении в об'явлении переменных: int a, b, c;
2. При перечислении параметров фукнции (макросов это тоже касается): int f(int a, int b, int c); -- и потом f(7,3,2).
3. При инициализации массивов и структур: int a[3]={1,2,3};
В Си++ есть ещё несколько случаев, но на них я останавливаться не буду.
Все остальные запятые -- это "операции запятые"!
Когда студенты спрашивают, почему я про неё рассказываю, когда от неё так мало пользы, я отвечаю, что по двум причинам:
1. Чтобы вы смогли её опознать в чужом тексте, если какой-нибудь умник её применит.
2. Чтобы сами не писали её там, где её быть не нужно, ожидая иного поведения (об этом, собственно, данная статья).
Как работает эта штука -- несколько выражений пишутся через запятую. При вычислении общего выражения каждое из них вычисляется последовательно слева направо (они могут быть разных типов), при этом каждое из них вычисляется обязательно, а результат -- это результат последнего выражения; результаты всех остальных выражений выбрасываются на помойку, хотя то, что они изменили (присваивание и т.п.) -- сохраняется. У операции "запятая" самый низкий приоритет. Последнее очень важно.
(примеры)Пример 1.
a=2,b=3;
В a 2, в b 3, результат -- 3.
Пример 2.
2,3;
Результат -- 3.
Пример 3.
a=3,b=a+3,7;
В a 3, в b 6, результат -- 7.
Пример 4.
a=3+5,3+7;
Вот тут очень важный момент. У "запятой" минимальный приоритет, поэтому сначала выполняется присваивание и в a 8, но результат операции 10. Я всё говорю про результат, но как его получить-то, когда даже присваивание выполняется раньше? Искусственно поменять приоритет.
Пример 5.
a=(3+5,3+7);
В a -- 10, результат выражения -- 10.
Можно долго распинаться о пользе этой операции, но за меня это уже сделали. Пожалуйста: iproc.ru/programming/cpp-comma-operator/ .
Я остановлюсь на факапах, которые происходят по её вине. Чаще всего это бывает у очень сильно начинающих писать на Си (Си++, PHP, Java, Javasсript -- вас всех это тоже касается!). Часто вижу на примере студентов.
Начнём с безобидного.
Факап 1. for(x=0,x<100,x++)
Не знаю, что заставляет писать так. Видимо, пишется по памяти. Но после написания 2-3 рабочих циклов такого уже не должно происходить. Почему безобидное, потому что не будет компилироваться.
Факап 2. return a,b;
Хочется вернуть два значения сразу! Но нельзя. Вернётся b. Когда это увидел ssvda, он сказал, что автору данной строки нужно учить Python, там такое работает.
Я, правда, применяю подобную конструкцию в виде return printf("Error opening file\n"),ERROR_FILE_OPEN;
В одну строчку выводит сообщение об ошибке и возвращает её код. За такое надо убивать (меня).
Факап 3. int volume, r=3; volume=4/3*3,14*r^3;
Эти не знают, что в Си -- десятичная точка, а не запятая. И ещё не знают, что крышка -- это поразрядное исключающее "или". В volume будет 3. Про об'ём как целое число -- ладно, фиг с ним.
Факап 4. int a[3][3]; a[1,2]=0;
Для тех, кто раньше писал на Паскале/Делфи, МАТЛАБе и чёрт знает чём ещё может быть совершенно неочевидно, что в данном случае тоже! применяется операция запятая. a[1,2] эквивалентно a[2]. Но a[2] имеет тип const int *. Не скомпилируется. Но если многомерный массив -- динамический, то даже предупреждения не будет.
Факап 5. while(a>3, c>2)
Имелось ввиду while(a>3&&c>2). В данном случае будет проверяться лишь второе условие.
Факап 6. Приплюснутое. delete t1,t2;
delete -- такая же операция, как и остальные и тоже имеет свой ранг в таблице приоритетов. Поэтому сначала будет вычислено delete t1 (указатель удалён, результат: void), потом t2 (результат: t2), а результатом будет последнее выражение (t2). t2 удалён не будет! (спасибо за поддержку: himself)
Факап 7. Приплюснутое, часть 2. throw 1, 2;
См. факап 6. То же.
Разумеется, минимально-опытный программист крайне редко будет писать подобные штуки, но, возможно, это поможет кому-нибудь найти (и об'яснить, что важно!) смешную ошибку у коллег/подопечных, либо во время изучения Си и связанных языков.
@темы:
Программирование,
Статьи
12.12.2014 в 00:01
12.12.2014 в 00:03
12.12.2014 в 02:37
Я не программист, да ещё и гуманитарий. Для меня человек, который понимает что-то в этих заклинаниях - гуру (если не считать, что однажды я сам для себя написал мод к Hearts of Iron III (но там было руководство по написанию модов)).
17.01.2015 в 13:27
-- Minoru
16.11.2020 в 13:51