Evg |
СОДЕРЖАНИЕ
Как работает оператор switch в Си/Си++
Запись от Evg размещена 15.02.2012 в 20:36
Показов 254923
Комментарии 24
|
ВНИМАНИЕ! Вопросы по существу обсуждаемого вопроса просьба задавать здесь или создать тему на форуме и кинуть на неё ссылку в блог или мне в личку.
Объясняю почему
Причин для этого несколько. Я, как и любой другой автор, всегда могу упустить интересный момент обсуждаемой темы (что подтвердилось на практике). А потому задаваемый вопрос может закрывать пробел в статье. Ответ на конкретный вопрос, как правило, дать несложно. Сложнее его аккуратно сформулировать так, чтобы ответ являлся законченной частью статьи. Поэтому, как правило, на первых порах я ограничиваюсь конкретным ответом на конкретный вопрос, а в статью временно вставляю ссылку на пост, где был дан ответ. А когда дойдут руки, то вместо ссылки пишу нормальное пояснение. Технические возможности блога не позволяют в комментариях пользоваться широкими возможностями, доступными на форуме (то как выделение текста жирным, вставка фрагментов исходников в удобном для чтения виде и т.п.), поэтому будет удобнее, если вопрос и ответ будут опубликованы на форуме Любая статья является изложением знаний в общем случае. У многих людей мышление устроено так, что прочтя на форуме конкретный вопрос и конкретный ответ на этот вопрос, у них появится бОльшее понимание, чем после прочтения теоретических выкладок (даже если они подкреплены конкретными примерами). Ссылки на такие обсуждения я, как правило, включаю в последний раздел статьи. Начинающие, как правило, поиск ответов на свои вопросы ведут именно в форуме, а не в блогах. А потому конкретный вопрос и конкретный ответ для них будет более удобным и полезным именно на форуме. Многие люди умеют работать методом тыка, лишь бы был конкретный пример в качестве образца. А потому такое обсуждение будет им полезным даже без прочтения статьи Исторически сложилось, что раньше (когда ещё не было блога) статьи располагались на форуме и представлены были в виде двух тем. Первая тема создавалась в специально отведённой свалке и представляла собой черновик, который со временем дорабатывался до законченной статьи. После этого статья переезжала во вторую тему в тематическом разделе. А первая тема оставалась дополнительной свалкой для замечаний и мелких вопросов по теме. Ссылку на старое местоположение данной свалки я помещаю в начале статьи. Вопросы, по возможности, прошу создавать в отдельных темах, но если вопрос действительно мелкий, то можно его задать и в указанной свалке. 1. Как обычно поясняется работа switch'а в учебниках Так или иначе все программисты считают, что они знают ответ на этот вопрос. Однако это не так. В большинстве случаев знания почерпаны из книг и учебников или являются эмпирическими результатами самостоятельных исследований. Но, как показала практика, большинство программистов (к их числу когда-то относился и я) на самом деле не знают точной семантики (смысла) оператора switch. Начну с простого примера C switch (x) { case 10: y = 1; break; case 11: case 12: y = 2; break; default: y = 3; break; } C if (x == 10) { y = 1; } else if (x == 11 || x == 12) { y = 2; } else { y = 3; } Те, кто перешёл с Паскаля на Си, очень часто спотыкаются о необходимость расставлять break'и. В паскале конструкция case (а точнее, её альтернатива, ибо я не помню, как правильно в паскале писать) означает автоматическое завершение кода предыдущей альтернативы и уход на конец switch'а. В учебниках сей факт как правило поясняют тем, что break можно не ставить, и в этом случае произойдёт провал (fall) на следующую альтернативу. Ну и как частный случай - два подряд идущих case'а являются вырожденным случаем провала. Необходимость построения настоящих (невырожденных) провалов на практике является статистически редким явлением, и потому многих необходимость написания break'а сильно раздражает. 2. Как на самом деле работает switch Оператор switch на самом деле является коммутируем переходом. Т.е. в зависимости от значения ключа (то, что стоит в скобках после слова switch) происходит переход на ту или иную метку, а операторы case определяют эти самые метки. Продемонстрирую это на примере, содержащем в том числе провалы (отсутствие break'ов). C switch (x) { <--- скобка 1 case 10: y = 1; break; case 11: case 12: y = 2; /* break; */ <--- тут уберём break и устроим провал default: y = 3; break; } <--- скобка 2 C /* Данный набор операторов if и goto есть семантический эквивалент * оператора switch (x) */ if (x == 10) goto L10; else if (x == 11) goto L11; else if (x == 12) goto L12; else goto Ldefault; { <--- скобка 1 L10: <--- метка "case 10" y = 1; goto Finish; <--- break L11: <--- метка "case 11" L12: <--- метка "case 12" y = 2; /* goto Finish; */ <--- закомментированный break Ldefault: <--- метка "default" y = 3; goto Finish; <--- break } <--- скобка 2 Finish: <--- метка за пределами switch'а, куда ведут все break'и эта метка полностью эквивалентна тому, что есть в циклах for и while 3. То, о чём редко пишут в учебниках Поискав через google описание работы switch'а, я много раз натыкался на описание синтаксиса. Этот синтаксис сводится к следующему (здесь привожу вариант с MSDN): Code switch (expression) { case constant_expression_1 : statement_1; ... case constant_expression_n : statement_n; [default: statement_n+1] } Code if (expression) body Code while (expression) body Code switch (expression) body Теперь рассмотрим синтетический (т.е. не из реальной жизни) пример, который на первый взгляд многим может показаться диким, потому что идёт в разрез с имеющимся представлением о работе switch'а: C switch (x) if (z == 5) { case 10: y = 1; } else { case 11: if (z > 10) y = 2; else { default: y = 3; } } C if (x == 10) <--- начало оператора switch goto L10; else if (x == 11) goto L11; else goto Ldefault; <--- конец оператора switch if (z == 5) <--- начало "body" { L10: <--- метка "case 10" y = 1; } else { L11: <--- метка "case 11" if (z > 10) y = 2; else { Ldefault: <--- метка "Ldefault" y = 3; } } C switch (x) { int a, b; <--- переменные a и b доступны только внутри фигурных скобок case 10: a = x + 1; b = x - 1; y = a * b; break; ... } C void send (int *to, const int *from, int count) { int n = (count + 7) / 8; switch (count % 8) { case 0: do { *to++ = *from++; case 7: *to++ = *from++; case 6: *to++ = *from++; case 5: *to++ = *from++; case 4: *to++ = *from++; case 3: *to++ = *from++; case 2: *to++ = *from++; case 1: *to++ = *from++; } while (--n > 0); } } 4. Для чего придумали оператор switch С виду кажется, что switch в "нормальном" случае принципиально ничем не отличается от цепочки конструкций if - else if - ... По принципу действия действительно не отличается. Однако с точки зрения генерации кода switch принципиально строится по другому. Проще всего это опять пояснить на коротком примере. C switch (x) { case 5: y = 10; case 6: y = 25; case 7: y = 38; ... case 20: y = 125; default: y = 1000; } C /* Массив меток перехода на 16 альтернатив switch'а (от 5 до 20) */ static void *arr[16] = { &&L5, &&L6, &&L7, ..., &&L20 }; /* При таких значениях x мы попадаем в один из case'ов switch'а, * адрес для перехода загрузим из таблицы arr. При этом надо понимать, что * нулевой элемент таблицы соответствует значению x = 5. */ if (x >= 5 && x <= 20) goto *arr[x-5]; else goto L_default; L5: y = 10; L6: y = 25; L7: y = 38; ... L20: y = 125; L_default: y = 1000; Есть некоторые тонкие моменты, остающихся на усмотрение компилятора. Например, если в switch'е мы имеем всего две альтернативы 1 и 1000000, то таблица, построенная по такому принципу, занимала бы миллион слов (4 мегабайта в 32-битном режиме). Компилятор в таком случае вместо динамического перехода построит цепочку из двух if'ов. Есть ещё куча аналогичных моментов, которые я не стану описывать, потому что для общего понимания предназначения switch'а эти моменты не являются критичными 5. Ссылки на темы, где обсуждался данный вопрос |
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Всего комментариев 24
Комментарии
-
Эту штуку придумал не он: http://en.wikipedia.org/wiki/Duff's_device
Я считаю, что неплохим дополнением к твоей статье будет описание еще одного реального примера использования таких особенностей оператора switch — реализация простейших сопрограмм в ANSI C: оригинал, переводЗапись от Nameless One размещена 28.04.2012 в 07:37
-
Запись от Evg размещена 28.04.2012 в 20:19
-
кудлато. прошел по ссылкам выше.
это кусок оттуда
C++ (Qt) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
#define crBegin static int state=0; switch(state) { case 0: #define crReturn(i,x) do { state=i; return x; case i:; } while (0) #define crFinish } int function(void) { static int i; //crBegin; static int state=0; switch(state) { case 0: for (i = 0; i < 10; i++) //crReturn(1, i); do { state=1; return i; case 1:; } while (0); } } int main(int argc, char *argv[]) { QApplication a(argc, argv); qDebug()<<function()<<function()<<function()<<function()<<function()<<function(); return a.exec(); }
в общем первое и самое броское. ПОЧЕМУ эти д***бы любят запутывать людей? на кой туlа втыкать while.
все работает и БЕЗ него, достаточно скобочек. с while только еще более запутанно
выход тот жеC++ 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
int function(void) { static int i; static int state=0; switch(state) { case 0: //если state==0 ; for (i = 0; i < 10; i++) //входим в цикл увеличиваем i { //просто скобочки. открывают тело for state=1; //устанавливаем state = 1 return i; //возвращаем текущий i case 1:; //если state ==1 //то мы проскакиваем return и попадаем на окончание итерации фора, //далее новая итерация начинает выполнятся // идет увеличение счетчика i установка state (хотя онo и так 1) и возврат i //(из ругани компилятора я понял что ; нужно для закрытия метки) } //закрываeт тело for. } }
Огромное спасибо Nameless One за то что заострил внимание на этих примерах, там далее по ссылкам они расписали интересный механизм. Однако то что вот так втыкается лишний текст в и без того непростые примеры вызывает неприязнь к авторам. уже поздно а на досуге обязательно посмотрю для себя как оно работает.
Евгений сори за флуд.Запись от Pure размещена 28.04.2012 в 23:38
-
вообще-то, это распространенный (о нем даже в разных Coding-Style гайдах пишут) прием для написания макросов сложнее одной строчки (statement'а), и используют его не зря.
Сообщение от Pure
Можно привести пример. Пусть у нас есть гипотетический макрос, который выводит два выражения (и один вызов printf использовать нельзя):
Смотрим, какой код генерируется препроцессором (лишние переводы строки я буду удалять из листинга):C 1 2 3 4 5 6 7 8 9 10 11
int printf(const char*, ...); #define TEST(EXPR1, EXPR2) \ printf(#EXPR1 ": %d\n", (EXPR1)); \ printf(#EXPR2 ": %d\n", (EXPR2)) int main(void) { TEST(1 + 2, 1 / 2); return 0; }
Результат выполения программы очевиден, и я его приводить не буду.Bash 1 2 3 4 5 6 7 8 9 10 11 12 13
~/samples/c/temp $ cpp macro.c # 1 "macro.c" # 1 "<built-in>" # 1 "<command-line>" # 1 "macro.c" int printf(const char*, ...); int main(void) { printf("1 + 2" ": %d\n", (1 + 2)); printf("1 / 2" ": %d\n", (1 / 2)); return 0; } ~/samples/c/temp $
Изменим программу, чтобы макрос использовался в конструкции if:
C 1 2 3 4 5 6 7 8 9 10 11 12 13
int printf(const char*, ...); #define TEST(EXPR1, EXPR2) \ printf(#EXPR1 ": %d\n", (EXPR1)); \ printf(#EXPR2 ": %d\n", (EXPR2)) int main(void) { if(0) TEST(1 + 2, 1 / 2); return 0; }
будет неочевиден для новичка, но нам понятно, что это из-за того, что ветвь if не была обрамлена в фигурные скобки (блок).РезультатBash 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
~/samples/c/temp $ ./sample 1 / 2: 0 ~/samples/c/temp $ cpp macro.c # 1 "macro.c" # 1 "<built-in>" # 1 "<command-line>" # 1 "macro.c" int printf(const char*, ...); int main(void) { if(0) printf("1 + 2" ": %d\n", (1 + 2)); printf("1 / 2" ": %d\n", (1 / 2)); return 0; } ~/samples/c/temp $
Исправим это (тупо запихнув тело макроса в фигурные скобки).нас вроде бы устраивает. Но что, если нам нужно ввести в тот же if ветвь else?РезультатBash 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
~/samples/c/temp $ ./sample ~/samples/c/temp $ cpp macro.c # 1 "macro.c" # 1 "<built-in>" # 1 "<command-line>" # 1 "macro.c" int printf(const char*, ...); int main(void) { if(0) { printf("1 + 2" ": %d\n", (1 + 2)); printf("1 / 2" ": %d\n", (1 / 2)); }; return 0; } ~/samples/c/temp $
Программа не компилируется: получаем "«else» without previous «if»". Смотрим вывод препроцессора:C 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
int printf(const char*, ...); #define TEST(EXPR1, EXPR2) \ { \ printf(#EXPR1 ": %d\n", (EXPR1)); \ printf(#EXPR2 ": %d\n", (EXPR2)); \ } int main(void) { if(0) TEST(1 + 2, 1 / 2); else printf("Else clause. Have to be executed\n"); return 0; }
После блока стоит разделитель инструкций — точка с запятой, поэтому идущая следом ветвь else уже не может относится к if, в соответствии с грамматикой языка. Тут-то и приходит на помощь конструкция do-while():Bash 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
~/samples/c/temp $ cpp macro.c # 1 "macro.c" # 1 "<built-in>" # 1 "<command-line>" # 1 "macro.c" int printf(const char*, ...); int main(void) { if(0) { printf("1 + 2" ": %d\n", (1 + 2)); printf("1 / 2" ": %d\n", (1 / 2)); }; else printf("Else clause. Have to be executed\n"); return 0; } ~/samples/c/temp $
Результат:C 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
int printf(const char*, ...); #define TEST(EXPR1, EXPR2) \ do \ { \ printf(#EXPR1 ": %d\n", (EXPR1)); \ printf(#EXPR2 ": %d\n", (EXPR2)); \ } while(0) int main(void) { if(0) TEST(1 + 2, 1 / 2); else printf("Else clause. Has to be executed\n"); return 0; }
Так что одних скобочек недостаточно.Bash 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
~/samples/c/temp $ ./sample Else clause. Has to be executed ~/samples/c/temp $ cpp macro.c # 1 "macro.c" # 1 "<built-in>" # 1 "<command-line>" # 1 "macro.c" int printf(const char*, ...); # 10 "macro.c" int main(void) { if(0) do { printf("1 + 2" ": %d\n", (1 + 2)); printf("1 / 2" ": %d\n", (1 / 2)); } while(0); else printf("Else clause. Has to be executed\n"); return 0; } ~/samples/c/temp $
Запись от Nameless One размещена 29.04.2012 в 04:31
-
Про конструкцию "do { ... } while (0)" я уже как-то пояснял тут в разделе 2.5Запись от Evg размещена 29.04.2012 в 11:51
-
Запись от Catstail размещена 29.04.2012 в 15:09
-
Запись от Pure размещена 30.04.2012 в 16:33
-
Запись от Nameless One размещена 30.04.2012 в 16:35
-
в общем если подвести резюме то мы с Nameless One говорили о разном но в процессе сей беседы я познал
интересный трюк. НО.. возвращаюсь к тому что я хотел сказать по поводу данного конкретного примера
выход 3 2 1 0C++ (Qt) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
#define crBegin static int state=0; switch(state) { case 0: #define crReturn(i,x) { state=i; return x; case i:;} #define crFinish } int function(void) { static int i; crBegin; for (i = 0; i < 10; i++) crReturn(1, i); crFinish } int main(int argc, char *argv[]) { QApplication a(argc, argv); qDebug()<<function()<<function()<<function()<<function(); return a.exec(); }
итого в ДАННОМ КОНКРЕТНОМ ПРИМЕРЕ не нужен do while(0). в теле макроса хватит и просто скобок.
ругательные слова в адрес авторов возвращать не буду, так как далее по тексту в ссылке идут примеры с ифами, но в том, который я пытался разобрать - while(0) лишнийЗапись от Pure размещена 30.04.2012 в 23:28
-
Конструкция do-while(0) нужна для всех макросов сложнее одного statetement-а (кроме специфических случаев, как с сrBegin). Может, для данной функции фигурных скобок и хватит, но в if-else макрос не скомпилируется:
Если определить при компиляции макрос EVIL_MACRO, то препроцессор определит твою версию макроса со скобками, и программа не скомпилируется:C 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
#include <stdio.h> #include <limits.h> #include <stdlib.h> #define crBegin static int state = 0; switch(state) { case 0: #define crFinish } #ifndef EVIL_MACRO #define crReturn(x) \ do \ { \ state = __LINE__; \ return (x); \ case __LINE__: ; \ } while(0) #else #define crReturn(x) \ { \ state = __LINE__; \ return (x); \ case __LINE__: ; \ } #endif int func(void) { static int i; crBegin; for(i = 0; i < 10; ++i) if(i & 1) crReturn(i); else crReturn(-i); crReturn(INT_MAX); crFinish; } int main(void) { int result; while((result = func()) != INT_MAX) printf("%d\n", result); exit(0); }
Вывод: версия с do-while(0) будет работать везде, где работает версия с фигурными скобками, а также во всех остальных случаях.Bash 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
~/samples/c $ make main # версия с do-while(0) cc main.o -o main ~/samples/c $ ./main 0 1 -2 3 -4 5 -6 7 -8 9 ~/samples/c $ rm main ~/samples/c $ CFLAGS="-DEVIL_MACRO" make main # версия со скобками cc -DEVIL_MACRO main.c -o main main.c: В функции «func»: main.c:33:9: ошибка: «else» without a previous «if» make: *** [main] Ошибка 1 ~/samples/c $
Ну и в заключение цитата из Linux Kernel Coding Style:
Запись от Nameless One размещена 01.05.2012 в 03:47
-
прежде хочу сказать что про то, что как бы надо оборачивать в do while(0) я почерпнул из твоих постов, заметок Евгения и твоих ссылок. Но раз ты не перестаешь повторять это. то прокомментируй ВЫХОД
обрати внимание на эвил макро, он без всяких там do while(0). да чего уж там придумывать это считай целиком представленная тобой же для теста функция.Запись от Pure размещена 01.05.2012 в 18:13
-
На самом деле непонимание оно от незнания. Один раз в учебнике не так объяснили, и такие знания прижились на всю жизнь. Если человеку объяснить, то большинство, как мне кажется, логику поймут сразу
Сообщение от Catstail
Думаю, что в современных бэйсиках, поддерживающих нумерованные строки, оператор ON ... GOTO никуда не делся
Сообщение от Catstail
Запись от Evg размещена 02.05.2012 в 00:40
-
Запись от Nameless One размещена 02.05.2012 в 02:44
-
ты серьезно чтоли?
т.е. вот так надо писать?C++ 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
if(i&1) { state = __LINE__; return (i); case __LINE__: ; }; else { state = __LINE__; return (-i); case __LINE__: ; };
вот уж не подумал бы что это называется гуд практис. иметь точку с запятой после скобарей ифа да еще чтоб это все работало из*бываться с do while(0) в макросе.
Для кого Евгений старался расказывая во что разворачиваются макросы?
В общем то всей писаниной я хотел лишь напомнить, что авторитеты они хороши, но не забывайте о личной практике. И перед тем как делать перепост, поэксперементируйте немного. А то ведь кто то прочитав громкие слова примет на веру.Запись от Pure размещена 02.05.2012 в 22:05
-
> т.е. вот так надо писать?
Он имел в виду вот так:
И после этого оно работать перестанет. Можно писать как ты без ";", но оно выглядеть будет коряво. Собственно, имелось в виду только этоC 1 2 3 4 5
for(i = 0; i < 10; ++i) if(i&1) crReturn(i); /* <--- вот тут поставь ";" */ else crReturn(-i); /* <--- и вот тут ";" */
Запись от Evg размещена 02.05.2012 в 22:44
-
Евгений перестань. понимая во что разворачивается макрос не станешь себе придумывать допзадание поставить запятые и еще обернуть его . В этом примере увидев разворот макроса становится ясно что мы нарушаем как раз таки стиль языка ставя тчк.запятую в иф и усложняем себе жизнь оборачивая в do while(см.разворот постом выше). Думаю ты понял о чем я. Ты же сам учил что макрос это просто текст.
И коряво выглядит и тяжелее воспринимается усложненный обернутый разворот.
х*рь. еще пару инструкций и совсем тоскливо будет.C++ 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
for(i = 0; i < 10; ++i) if(i&1) do { state = __LINE__; return (i); case __LINE__: ; }while(0); else do { state = __LINE__; return (-i); case __LINE__: ; } while(0);
И пожалуй еще что хотел отметить. Очень категорично со стороны Nameless звучало что без do while(0) в этих примерах что мы разбирали никак НЕЛЬЗЯ обойтись, что странно. Это неправильно на мой взгляд так искажать информацию. И ради (непонятно за каким хреном), точки запятой (которая разрывает искусственно иф) надо усложнять этот конкретный макрос.
Давайте уже подведем итог и не будем стыдится и писать "он имел ввиду то или это". То что в цитате - это просто брехня, как показала суровая реальность. Будем добрее и честнее друг к другу. Думаю так будет лучше и информативнее
Сообщение от Nameless One
Запись от Pure размещена 02.05.2012 в 22:49
-
в том то и дело, что для того, чтобы правильно воспользоваться твоим макросом, нужно точно представлять, как он работает. Т.е. гипотетический пользователь, который будет пользоваться твоей супер-пупер библиотекой, обязан будет знать, что: 1) crReturn — это макрос; 2) после него никогда нельзя ставить точку с запятой (что выглядит коряво и непривычно с точки зрения языка). И не дай Б-г он забудет про это правило, или поставит точку с запятой на автомате — его ждет очень «содержательное» сообщение об ошибке.
Ок, согласен, чтобы пользователь мог нормально использовать твой макрос, он должен обязательно знать, во что он разворачивается, и никак иначе — ведь в противном случае он не застрахован от ошибок.
А ты разве не понимаешь, что пользователь разворот макроса не видит? Он видит только вызов макроса (да ему по сути и не надо знать, что это макрос).
еще раз повторяю, что ты можешь писать так для себя так, как хочешь. Главное, другим не показывай — засмеют ведь.Запись от Nameless One размещена 03.05.2012 в 03:15
-
Мне всегда казалось что свич реализует собой следующую логику,
ОтработкаC 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
#include <stdlib.h> #include <stdio.h> #include <time.h> int main() { srand(time(0)); int x = 0; while(1) { x = rand()%10; switch(x) { case 1:printf("case 1\n");break; case 2:printf("case 2\n");break; case 3:printf("case 3\n");break; case 4:printf("case 4\n");break; case 5:printf("case 5\n");break; case 6:printf("case 6\n");break; case 7:printf("case 7\n");break; case 8:printf("case 8\n");break; case 9:printf("case 9\n");break; default:printf("your input is not in interval 1-9\n");break; } if(x == 1)//case 1 printf("case 1\n"); else if(x == 2)//case 2 printf("case 2\n"); else if(x == 3)//case 3 printf("case 3\n"); else if(x == 4)//case 4 printf("case 4\n"); else if(x == 5)//case 5 printf("case 5\n"); else if(x == 6)//case 6 printf("case 6\n"); else if(x == 7)//case 7 printf("case 7\n"); else if(x == 8)//case 8 printf("case 8\n"); else if(x == 9)//case 9 printf("case 9\n"); else//default printf("your input is not in interval 1-9\n"); system("pause"); } return 0; }
Запись от -=ЮрА=- размещена 03.05.2012 в 16:50
-
пойми и ты. если ты пишешь что то на форуме, да еще "авторитетно" обосновываешь, то как минимум ты сам должен это проверить.
Сообщение от Nameless One
Что угодно и как угодно и где угодно можешь писать и ты. По моему это право каждого. Однако если взялся нести информацию - то проверь прежде чем писать, ошибся - так признай и прими во внимание. А то после таких постов (имею ввиду все посты после того как макрос таки скомпилировался да еще и отработал) ты выглядишь мягко говоря неубедительно и заявления про тру стайл выглядят еще менее убедительными. Так что пусть каждый прочитает эту длинную переписку и сам делает выводы как ему писать, а не просто ходит с лапшой про гуд практис, про то как надо и про то как не надо.Запись от Pure размещена 03.05.2012 в 19:41
-
Pure, я от своих слов не отказываюсь. Единственное, что мне нужно было уточнить заранее — это, что вызов макроса будет завершаться точкой с запятой, чтобы код был консистентным (тот пост я исправлять уже, понятное дело, не буду). Но это подразумевалось как наиболее естественный вариант (и это можно увидеть в моем сообщении), т.к. вызов макроса без точки с запятой в таком тривиальном случае — нонсенс. А то, что даже для тебя вызов вызов макроса без точки с запятой выглядит неестественно, можно видеть хотя бы по тому, что ты сам ее ставил после своего макроса до тех пор, пока я тебе явно не указал на случай, когда он с ним не скомпилируется. После этого точка с запятой внезапно пропала, и ты начал говорить о моей некомпетентности.
самое смешное в этой ситуации — это то, что мне и в самом деле не нужно «защищать» макросы с do-while(0) против твоей версии, так как это действительно распространенная практика (ты, естественно, можешь мне не верить на слово, как и любой другой, кто это прочитает)
Но ты прав:
Так что, полагаю, наша дискуссия окончена, и каждый остался при своем мнении. Всего хорошего.Запись от Nameless One размещена 04.05.2012 в 02:26

интересный трюк. НО.. возвращаюсь к тому что я хотел сказать по поводу данного конкретного примера
ты серьезно чтоли? 
