On-line: гостей 2. Всего: 2 [подробнее..]
Программисты всех стран, объединяйтесь!

АвторСообщение



ссылка на сообщение  Отправлено: 28.07.12 17:54. Заголовок: Код, который не следует писать, но нужно знать!


На создание этой темы меня подвигли достаточно курьезный и забавный код и соответсвующий баг компилятора 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"

Хоть я и не согласен с автором изначального сообщения, что такой код можно использовать в своих программах, тем не менее он заслуживает благодарности за интересный пример!


Спасибо: 0 
ПрофильЦитата Ответить
Новых ответов нет


Ответ:
1 2 3 4 5 6 7 8 9
большой шрифт малый шрифт надстрочный подстрочный заголовок большой заголовок видео с youtube.com картинка из интернета картинка с компьютера ссылка файл с компьютера русская клавиатура транслитератор  цитата  кавычки моноширинный шрифт моноширинный шрифт горизонтальная линия отступ точка LI бегущая строка оффтопик свернутый текст

показывать это сообщение только модераторам
не делать ссылки активными
Имя, пароль:      зарегистрироваться    
Тему читают:
- участник сейчас на форуме
- участник вне форума
Все даты в формате GMT  3 час. Хитов сегодня: 3
Права: смайлы да, картинки да, шрифты да, голосования нет
аватары да, автозамена ссылок вкл, премодерация откл, правка нет