На создание этой темы меня подвигли достаточно курьезный и забавный код и соответсвующий баг компилятора
Intel. Исходное описание проблемы, приведенное Alexey Sudachen, можно прочитать по ссылке
http://www.rsdn.ru/?/forum/cpp.applied/ Чем так забавен и курьезен этот случай? Забавен он тем, что код из примера, во-первых, вряд ли когда-нибудь встретишь в реальном проекте (хотя автор исходной темы утверждает обратное), и, во-вторых, с моей точки зрения такой код не следует вообще никогда писать.
Почему не следует никогда писать такой код? Потому что он нарушает принципы структурного программирования, и конструкция структурного программирования
switch превращается совершенно в неструктурную конструецию, имитирующую оператор
goto. То есть в примере, который будет приведен ниже, фактически, с помощью завуалированного оператора
goto управление передается внутрь структурных конструкций, как, например, управляющего предложения
while.
Но хуже того такой код очень тяжело воспринимать, и, чтобы понять, что этот код делает, а также чтобы правильно его трактовать, потребуется немало умственных усилий и знание стандарта языка С.
Так как обычно такой код редко, когда встретишь, то есть когда управление с помощью завуалированного оператора
goto передается внутрь управляющей конструкции, то многие программисты сходу не в состоянии оценить все семантические тонкости таких конструкций и более того даже не могут сказать, является ли код сиинтаксически корректным!
Вот исходный пример, написанный на С
#include <stdio.h>
int main( void )
{
puts( "--- 1 ---" );
switch ( 0 )
if ( 1 ) case 0: puts( "0" );
else default: puts( "default" );
puts( "--- 2 ---" );
switch ( 0 )
while ( 0 )
if ( 1 ) case 0: puts( "0" );
else default: puts( "default" );
return ( 0 );
}
Глядя на этот код, сразу же возникают сомнения, а будет ли он вообще компилироваться?!
Но на самом деле, каким бы вычурным этот код не казался, но с синтаксической точки зрения он является корректным!
Теперь нужно разобраться, как этот код должен работать, и какой результат следует ждать от выполнения программы.
В первом случае в соответсвии с семантикой оператора
switch управление перейдет по метке
case 0 внутрь оператора
if. В связи с чем будет напечатан строковый литерал
"0".
Теперь возникает вопрос, а куда дальше перейдет управление программы? Например, будет ли напечатан строковый литерал
"default"? Здесь уже без непосредственного обращения к тексту описания стандарта С не обойтись!
Что написано в стандарте по этому поводу? Читаем (6.8.4.1 The if statement #2):
"If the first substatement is reached via a label, the second substatement is not executed." Итак, строковый литерал "default" не должен печататься.
С первым случаем мы разобрались. Теперь рассмотрим второй случай. Во втором случае переход по метке сразу же перескакивает внутрь двух управляющих конструкций:
while и
if. С
if мы разобрались: будет печататься строковый литерал "0", а предложение
else будет пропущено.
Теперь возникает вопрос, а как ведет себя
while , если управление в него попало по метке внутрь тела. Опять-таки, без непосредственного обращения к стандарту не обойтись! Читаем (6.8.5 Iteratins statements #4):
"The repetition occurs regardless of whether the loop body is entered from the iteration statement or by a jump" Следовательно после выполнения
puts( "0" ) управление перейдет к
while, в котором условие является ложным, а потому на этом выполнения данного кода закончится.
Итак, в обоих случаях должен печататься строковый литерал
"0". Второй случай можно сделать более интересным, если его слегка изменить.
#include <stdio.h>
int main( void )
{
int x = 0;
puts( "--- 2 ---" );
switch ( 0 )
while ( x )
if ( !x ) case 0: puts( "0" ), ++x;
else default: puts( "default" ), --x;
return ( 0 );
}
В этом случае сначала напечатается строковый литерал
"0". При этом
x станет равным
1. Управление перейдет на
while. Условие будет истинным, а потому мы снова попадет внутрь тела
while. На этот раз управление получит оператор
else, и будет напечатан строковый литерал
"default".
x станет равным
0, и управление выйдет из тела
while.
Естественно любопытно, а почему появилось изначальное сообщение по указанной ссылке?
Дело в том, что компилятор
Intel дает другой результат!. В первом случае он печатает
'0" "default" А во-втором случае, как и полагается, только
"0" Хоть я и не согласен с автором изначального сообщения, что такой код можно использовать в своих программах, тем не менее он заслуживает благодарности за интересный пример!