#cpp #c #language_lawyer #system #неопределенное_поведение
Смотрю описание функции system и заметил два странных места: If command is not a null pointer, the value returned depends on the system and library implementations, but it is generally expected to be the status code returned by the called command, if supported. Что подразумевается под "generally expected"? В каких случаях может оказаться, что возвращаемое значение не является кодом возврата? И чем оно тогда является? If command is not a null pointer, it causes undefined behavior. Но ведь функция для того и нужна, чтобы выполнять команды, которые, очевидно, не null. О каком же неопределённом поведении и при каких условиях идёт речь? PS: В другом источнике возвращаемое значение вообще не связывается с выполняемой командой (если она не null) - говорится просто "Implementation-defined value". И никаких упоминаний про UB.
Ответы
Ответ 1
Если посмотреть в черновик стандарта С++ (N4791), то можно найти всего лишь пару скудных упоминаний функции system. В разделе 16.2.2, описывающем заголовочный файл. И там просто представлена её сигнатура: int system(const char* string); В разделе 16.12 Other runtime support: Headers (nonlocal jumps), (signal handling), (variable arguments), and (runtime environment getenv, system), provide further compatibility with C code. Собственно, из п.2. становится ясно, что искать описание надо уже в сишном стандарте. Ну а там (С11) мы видим следующее (7.22.4.8): Description If string is a null pointer, the system function determines whether the host environment has a command processor. If string is not a null pointer, the system function passes the string pointed to by string to that command processor to be executed in a manner which the implementation shall document; this might then cause the program calling system to behave in a non-conforming manner or to terminate. Returns If the argument is a null pointer, the system function returns nonzero only if a command processor is available. If the argument is not a null pointer, and the system function does return, it returns an implementation-defined value. Можно заметить, что никаких упоминаний UB тут нет, но есть требование к реализации предоставить соответствующую документацию о том, как должен работать командный процессор, вызванный через system и есть ли он вообще. А еще есть фраза очень похожая по возможному исходу на UB: ... to behave in a non-conforming manner or to terminate. Мой перевод: ... вести себя несоответствующим образом или завершиться. Но в силу того, что это всё отдано на откуп реализации - это не является UB с точки зрения стандарта языка. Т.о. в случае затруднений с интерпретацией всё же стоит обращаться к стандарту (хотя бы черновику), а не рассчитывать на описания с других сайтов. Ради интереса я посмотрел в web архиве версию страницы cplusplus.com от ноября 2012 года и там про UB тоже ничего нет. Вполне допускаю, что в текущей версии страницы просто решили таким простым образом расшифровать вышеупомянутую мной фразу. Например, ситуация с system(nullptr) является переносимой, а всё остальное - нет и жди беды. Насчёт "generally expected" вроде бы уже ответили, суть в том, чтобы не перекладывать поведение системы, где будет выполняться скомпилированный код, на стандарт языка, поэтому предложен некий наиболее известный случай. А что там понапишут какие-то другие реализации, и что в них должен значить этот код - дело уже самих реализаций, а не языка С. Ответ 2
В общем случае язык не требует, чтобы в среде выполнения вообще существовало такое понятие, как "код возврата команды". Может в командном процессоре среды выполнения никакого "кода возврата" не поддерживается вообще или используемый подход к возврату статуса завершения не является натурально совместимым с типом int. Поэтому навязывать такое требование спецификация языка не может/не хочет. P.S. Спецификация такого поведения по своей общей сути аналогична, например, спецификации преобразований между указательными и целыми типами. Всем понятно, что в общем и целом ожидается просто преобразование значения адреса. Но спецификация языка не оговаривает деталей внутреннего представления указателей и не хочет навязывать такое поведение. Откуда взялось упоминание про "undefined behavior" - надо разбираться. В стандарте языка я такого прямого утверждения не вижу. Хотя определенная логичность в нем есть: выполнение команды командным процессором может привести к каким угодно результатам и описание поведения таких команд выходит за рамки implementation-defined.
Комментариев нет:
Отправить комментарий