В статье есть небольшая проблема логики.
Он (правильно) определяет, что определенное использование функций C имеет поведение, которое не определено в ISO C. Но затем, чтобы избежать этого неопределенного поведения, в статье предлагается решение: заменить это использование функциями, специфичными для платформы. К сожалению, использование специфичных для платформы функций также не определено в соответствии с ISO C. Следовательно, совет не решает проблему неопределенного поведения.
Цитата в моей копии стандарта 1999 года подтверждает, что предполагаемое поведение действительно не определено:
Двоичный поток не нуждается в значимой поддержке вызовов fseek со значением откуда SEEK_END. [ISO 9899: 1999, пункт 7.19.9.2]
Но неопределенное поведение не означает «плохое поведение»; это просто поведение, для которого стандарт ISO C не дает определения. Не все неопределенные поведения одинаковы.
Некоторые неопределенные варианты поведения - это области языка, в которых могут быть предоставлены значимые расширения. Платформа заполняет пробел, определяя поведение.
Предоставление рабочего fseek
, который может искать из SEEK_END
, является примером расширения вместо неопределенного поведения. Можно подтвердить, поддерживает ли данная платформа fseek
из SEEK_END
, и если это предусмотрено, то можно использовать ее.
Предоставление отдельной функции, такой как lseek
, также является расширением вместо неопределенного поведения (неопределенное поведение вызова функции, которая не находится в ISO C и не определена в программе на C). Это хорошо использовать, если доступно.
Обратите внимание, что те платформы, которые имеют функции, такие как POSIX lseek
, также, вероятно, будут иметь ISO C fseek
, который работает с SEEK_END
. Также обратите внимание, что на платформах, где fseek
в двоичном файле не может искать от SEEK_END
, вероятная причина в том, что это невозможно сделать (не может быть предоставлен API для этого, и поэтому функция библиотеки C fseek
не может его поддержать).
Итак, если fseek
обеспечивает желаемое поведение на данной платформе, то ничего не нужно делать с программой; это бесполезная попытка изменить его для использования специальной функции этой платформы. С другой стороны, если fseek
не обеспечивает поведение, то, скорее всего, ничего не дает, в любом случае.
Обратите внимание, что даже включение нестандартного заголовка, которого нет в программе, является неопределенным поведением. (Опущением определения поведения.) Например, если в программе на Си появляется следующее:
#include <unistd.h>
поведение после этого не определено. [См. Ссылки ниже.] Поведение директивы предварительной обработки #include
определено, конечно. Но это создает две возможности: либо заголовок <unistd.h>
не существует, и в этом случае требуется диагностика. Или заголовок существует. Но в этом случае содержимое неизвестно (что касается ISO C; такой заголовок для Библиотеки не задокументирован). В этом случае директива include вводит неизвестный кусок кода, встраивая его в модуль перевода. Невозможно определить поведение неизвестного фрагмента кода.
#include <platform-specific-header.h>
является одним из аварийных люков в языке для выполнения каких-либо действий на данной платформе.
В форме точки:
- Неопределенное поведение не является «плохим» и не является недостатком безопасности (хотя, конечно, это может быть! Например, переполнение буфера связано с неопределенным поведением в области арифметики и разыменования указателей.)
- Замена одного неопределенного поведения другим, только во избежание неопределенного поведения, бессмысленна.
- Неопределенное поведение - это просто специальный термин, используемый в ISO C для обозначения вещей, выходящих за рамки определения ISO C. Это не означает «никто не определен в мире» и не означает, что что-то является дефектным.
- Использование большинства неопределенных поведений необходимо для создания большинства реальных полезных программ, поскольку многие расширения предоставляются посредством неопределенного поведения, включая заголовки и функции, специфичные для платформы.
- Неопределенное поведение может быть заменено определениями поведения вне ISO C. Например, серия стандартов POSIX.1 (IEEE 1003.1) определяет поведение включения
<unistd.h>
. Неопределенная программа ISO C может быть четко определенной программой POSIX C.
- Некоторые проблемы невозможно решить в C, не полагаясь на какое-то неопределенное поведение. Примером этого является программа, которая хочет получить столько байтов назад от конца файла.
Ссылки
- Дэн Поп в comp.std.c, декабрь 2002: http://groups.google.com/group/comp.std.c/msg/534ab15a7bc4e27e?dmode=source
- Крис Торек, comp.std.c, на тему нестандартного поведения нестандартного поведения, февраль 2002 г .: http://groups.google.com/group/comp.lang.c/msg/2fddb081336543f1?dmode=source
- Крис Энгебретсон, comp.lang.c, апрель 1997: http://groups.google.com/group/comp.lang.c/msg/3a3812dbcf31de24?dmode=source
- Бен Пфафф, comp.lang.c, декабрь 1998 г. [Шутливый ответ со ссылкой на неопределенность включения нестандартных заголовков]: http://groups.google.com/group/comp.lang.c/msg/73b26e6892a1ba4f?dmode=source
- Lawrence Kirby, comp.lang.c, сентябрь 1998 г. [Объясняет влияние нестандартных заголовков]: http://groups.google.com/group/comp.lang.c/msg/c85a519fc63bd388?dmode=source
- Кристиан Бау, комп.