Знаменитый глюк
14/03/2009 10:36Поскольку писать мне пока особо не о чем, и к тому же я нахожусь в некотором отупении от (заканчивающейся) простуды, то пост будет программистский.
Недавно в комментах у
rexy_craxy я упомянул о знаменитой ошибке в программе на FORTRAN IV, из-за которой не то НАСА потеряло спутник, не то американские военные — ракету (не помню точно). Расскажу поподробнее.
Вот кусок программы на Фортране:
Это цикл с переменной-счётчиком I, принимающей значения от 1 до 5 (а 20 — это метка последнего оператора тела цикла, в данном случае пустого оператора CONTINUE). Тут всё нормально.
Но вспомним, что запятая и точка на клавиатуре расположены рядом. И вот однажды программист опечатывается и вместо запятой вводит точку:
Как ни покажется странным, этот кусок нормально проходит компиляцию. Почему? Да потому, что 1) в Фортране пробелы внутри идентификаторов ничего не значат, 2) переменные в Фортране можно не объявлять (их тип определяется по первой букве идентификатора). В результате первая строка теперь означает присваивание числа 1.5 переменной DO20I (типа FLOAT).
В результате происходит следующее: присваивание числа некоей далее не используемой переменой, выполнение операторов один раз (к тому же переменной I, вероятно, уже было выше присвоено какое-то значение, так что ошибки не происходит) и... всё. Т. е. вместо цикла получаем однократное выполнение тела цикла со "случайным" значением переменной-счётчика.
Компилятор на такую ошибку не ругается. Ошибок времени выполнения тоже не происходит. Представьте, насколько трудно отловить такую ошибку, особенно при тогдашней (60-х годов) технике отладки программ (а если это всё было на перфокартах?!)
Вот так вот ошибка, допущенная при разработке синтаксиса языка, провоцирует трудноотлавливаемые ошибки при программировании. И программиста, допустившего такую ошибку, просто грех ругать чайником и т.п. Ему только посочувствовать можно. Я считаю, что в таком случае не программист виноват, а язык программирования (точнее, его разработчики). (Кстати, чтобы смягчить эффект, ЕМНИП, в FORTRAN-77 разрешили писать запятую перед переменной-счётчиком: DO 20, I=1,5; если запятую не писать, то компилятор выдавал предупреждение).
То же самое происходит и в C/C++. Но об этом я умолчу, т. к. фанаты C воспринимают наезд на своего кумира весьма болезненно :)
Практический вывод для меня такой: никогда не пренебрегать предупреждениями (warning'ами) компилятора. Современные компиляторы пытаются исправить такие ошибки в синтаксисе языка тем, что сомнительные (но допустимые с точки зрения синтаксиса) места пропускают, но помечают предупреждением. Так вот, я всегда стремлюсь не оставлять ни одного warning'а в своих программах — на любом языке. Даже если это всего лишь предупреждение о неиспользуемой переменной. Что и рекомендую всем.
Недавно в комментах у
![[livejournal.com profile]](https://www.dreamwidth.org/img/external/lj-userinfo.gif)
Вот кусок программы на Фортране:
DO 20 I=1,5 ... какие-то операторы ... 20 CONTINUE
Это цикл с переменной-счётчиком I, принимающей значения от 1 до 5 (а 20 — это метка последнего оператора тела цикла, в данном случае пустого оператора CONTINUE). Тут всё нормально.
Но вспомним, что запятая и точка на клавиатуре расположены рядом. И вот однажды программист опечатывается и вместо запятой вводит точку:
DO 20 I=1.5 ... какие-то операторы ... 20 CONTINUE
Как ни покажется странным, этот кусок нормально проходит компиляцию. Почему? Да потому, что 1) в Фортране пробелы внутри идентификаторов ничего не значат, 2) переменные в Фортране можно не объявлять (их тип определяется по первой букве идентификатора). В результате первая строка теперь означает присваивание числа 1.5 переменной DO20I (типа FLOAT).
В результате происходит следующее: присваивание числа некоей далее не используемой переменой, выполнение операторов один раз (к тому же переменной I, вероятно, уже было выше присвоено какое-то значение, так что ошибки не происходит) и... всё. Т. е. вместо цикла получаем однократное выполнение тела цикла со "случайным" значением переменной-счётчика.
Компилятор на такую ошибку не ругается. Ошибок времени выполнения тоже не происходит. Представьте, насколько трудно отловить такую ошибку, особенно при тогдашней (60-х годов) технике отладки программ (а если это всё было на перфокартах?!)
Вот так вот ошибка, допущенная при разработке синтаксиса языка, провоцирует трудноотлавливаемые ошибки при программировании. И программиста, допустившего такую ошибку, просто грех ругать чайником и т.п. Ему только посочувствовать можно. Я считаю, что в таком случае не программист виноват, а язык программирования (точнее, его разработчики). (Кстати, чтобы смягчить эффект, ЕМНИП, в FORTRAN-77 разрешили писать запятую перед переменной-счётчиком: DO 20, I=1,5; если запятую не писать, то компилятор выдавал предупреждение).
То же самое происходит и в C/C++. Но об этом я умолчу, т. к. фанаты C воспринимают наезд на своего кумира весьма болезненно :)
Практический вывод для меня такой: никогда не пренебрегать предупреждениями (warning'ами) компилятора. Современные компиляторы пытаются исправить такие ошибки в синтаксисе языка тем, что сомнительные (но допустимые с точки зрения синтаксиса) места пропускают, но помечают предупреждением. Так вот, я всегда стремлюсь не оставлять ни одного warning'а в своих программах — на любом языке. Даже если это всего лишь предупреждение о неиспользуемой переменной. Что и рекомендую всем.