Это один из тех странных угловых случаев, когда мы подвержены ограничениям английского языка и несогласованной структуре стандарта. Так что в лучшем случае я могу привести убедительный контраргумент, поскольку доказать это невозможно :) 1
Код в вопросе демонстрирует четко определенное поведение.
Поскольку [7.1.4] является основой вопроса, давайте начнем с этого:
Каждое из следующих утверждений применяется, если иное явно не указано в подробных описаниях, которые следуют: Если аргумент функции имеет недопустимое значение ( например, значение вне домена функции или указатель вне адресного пространства программы, или нулевой указатель , [... другие примеры ...] ) [...] поведение не определено. [... другие заявления ...]
Это корявый язык. Одна интерпретация состоит в том, что элементы в списке являются UB для всех библиотечных функций, если они не отменены отдельными описаниями. Но список начинается с «например», что указывает на то, что он иллюстративный, а не исчерпывающий. Например, в нем не упоминается правильное завершение строк нулевым символом (критично для поведения, например strcpy
).
Таким образом, ясно, что цель / область действия 7.1.4 просто состоит в том, что «недопустимое значение» приводит к UB ( если не указано иное ). Мы должны изучить описание каждой функции, чтобы определить, что считается «недопустимым значением».
Пример 1 - strcpy
[7.21.2.3] говорит только следующее:
В strcpy
функция копирует строку , указанную s2
(включая завершающий нулевой символ) в массив , на который указывает s1
. Если копирование происходит между перекрывающимися объектами, поведение не определено.
В нем нет явного упоминания нулевых указателей, но и нет упоминания о нулевых терминаторах. Вместо этого из «строки, на которую указывает s2
» делается вывод, что единственными допустимыми значениями являются строки (то есть указатели на массивы символов с завершающим нулем).
Действительно, эту закономерность можно увидеть в отдельных описаниях. Еще несколько примеров:
[7.6.4.1 (fenv)] сохранить текущую среду с плавающей точкой в указываемого объекта путемenvp
[7.12.6.4 (frexp)] хранить целое число в Int указываемого объекта с помощьюexp
[7.19.5.1 (fclose)] поток указал наstream
Пример 2 - printf
[7.19.6.1] говорит следующее %p
:
p
- Аргумент должен быть указателем на void
. Значение указателя преобразуется в последовательность печатаемых символов способом, определяемым реализацией.
Null - допустимое значение указателя, и в этом разделе явно не упоминается, что null - это особый случай, а также то, что указатель должен указывать на объект. Таким образом определяется поведение.
1. Если автор стандартов не явится, или если мы не сможем найти что-то похожее на документ с обоснованием, который проясняет ситуацию.