Как стандарты C и C++ предписывают вам действовать в ситуациях, которые ими не охвачены?

Хорошо известно, что в каждом из стандартов C и C++ были «слепые пятна», не описывающие определенные случаи в правильно построенных программах. Очевидно, что в неформальных описаниях столь сложных формальных систем невозможно предусмотреть все заранее.

По этой причине существует установленная процедура исправления и интерпретации стандарта до тех пор, пока не будет выпущена новая редакция («издание»). Давайте рассмотрим это на самом простом и хронологически первом примере — стандарте C90 (ISO/IEC 9899:1990), который сейчас официально отозван.

Для него были выданы следующие виды документов, в порядке убывания важности:

  1. Техническое исправление ISO (TC)

    По сути, это своего рода «заплатки», которые применяются непосредственно к существующему стандарту и имеют обратную силу. В действительности это означает, что все ранее совместимые реализации, по-своему интерпретировавшие расплывчатые части стандарта, становятся несовместимыми, если эти места каким-то иным образом будут разъяснены новыми документами.

    Для C90 было выпущено два таких документа: TC-1:1994 и TC-2:1996.

  2. Поправка ISO (Amd), также известная как Нормативное дополнение к ISO (NA)

    По своему эффекту он очень похож на TC и оказывает такое же воздействие, но может ограничивать его обратную силу с помощью какого-либо механизма, например введя новое значение __STDC_VERSION__.

    Обычно поправки ISO являются значительными и крупными, поэтому они выпускаются довольно редко. Но для С90 все равно был выпущен такой - Amd-1:1995.

  3. Отчет о дефектах WG14 (DR)

    Это письма в Комитет по стандартизации с просьбой разъяснить некоторые спорные места в стандарте, а также обратить внимание на разного рода недостатки в нем. Комитет обращается к ним, публично выражая свое коллективное мнение, которое может оказаться в официально утвержденном документе (ТК, НО или даже самом Стандарте).

    Однако сами Акты о дефектах не являются официальными документами и поэтому не имеют обязательной обратной силы. Тем не менее, разработчики и рядовые разработчики могут положиться на них, чтобы избежать несоответствия в будущем или, по крайней мере, снизить вероятность его возникновения.

    По стандарту С90, включая все вышеперечисленные дополнения, обработано 178 отчетов, списки которых доступны на официальном сайте комитета:
    https://www.open-std.org/jtc1/sc22/wg14/www/docs/dr.htm
    https://www.open-std.org/jtc1/sc22/wg14/www/docs/c90_drs.html


Поскольку стандарты не предусматривают эталонных (модельных) реализаций ни для компилятора, ни для стандартной библиотеки, это создает необходимость их постоянного уточнения и редактирования. Не все разработчики могут быть заинтересованы в полной поддержке новых стандартов, и не все разработчики хотят переписывать старый код, который они поддерживают — это факт жизни и бизнеса. Но также ясно, что TC и DR не могут выпускаться для старых стандартов бесконечно.

Таким образом, возникают следующие вопросы:

  1. Как обрабатывать недоопределенное поведение, которое явно не указано как определяемое реализацией, неуказанное или даже неопределенное?

  2. Следует ли использовать в таких случаях новые стандарты?

  3. Следует ли подавать отчет о дефектах для отмененного стандарта?

Обратите внимание, что я говорю не только о программистах компиляторов и стандартных библиотек, но и о обычных писателях кода.

Боюсь, эти слепые пятна остались в памяти разработчиков компиляторов.

πάντα ῥεῖ 16.09.2023 17:03

Эмпирическое правило: избегайте попадания кода в такие ситуации.

πάντα ῥεῖ 16.09.2023 17:08

Обычные авторы кода гораздо чаще сталкиваются с ошибками или ошибками производительности в компиляторах или стандартных библиотеках, чем в языковых стандартах. По моему опыту, вероятно, в 10 раз. Так что, особенно с точки зрения людей, пишущих код приложения, я думаю, что эти вопросы несколько неуместны. Но они, безусловно, интересны для разработчиков компиляторов и библиотек.

John Zwinck 16.09.2023 17:12

Поскольку, как вы написали, старые стандартные издания отозваны, я не думаю, что ISO даже предлагает какие-либо возможности для официальных исправлений к ним и считает их неуместными. Отчеты о дефектах включены в следующий стандарт или TC (что WG21 сделала, например, для C++03, но, похоже, больше не делает).

user17732522 16.09.2023 17:14

@user17732522 Официального заявления типа «по всем вопросам, не охватываемым этим стандартом, обратитесь к более поздним документам» комитета по стандартизации или самой ISO было бы более чем достаточно. Это полностью решило бы проблему.

cher-nov 16.09.2023 17:22

@DmitryD.Chernov Стандарт C90 официально помечен как «Отозван» на той самой странице, на которую вы ссылаетесь.

Andrew Henle 16.09.2023 17:28

@DmitryD.Chernov Я сомневаюсь, что это соответствует правилам и процедурам ISO. Поскольку ISO является организацией, они также строго определены. Но я ни в коем случае не эксперт в этом.

user17732522 16.09.2023 17:30

@AndrewHenle Да, я знаю. Мой вопрос касается проблемы, которая, по-видимому, является общей для всех стандартов C и C++, когда-либо опубликованных ISO.

cher-nov 16.09.2023 17:35

@cher-nov, ваш последний комментарий подсказывает мне, что, возможно, вы имеете в виду конкретный (предполагаемый) языковой недостаток и пытаетесь понять, как поступить с этой информацией. Если да, то я бы рекомендовал задать новый вопрос, в частности, о вашем предполагаемом недостатке.

John Bollinger 17.09.2023 22:02

@JohnBollinger Нет, под «проблемой» выше я имел в виду отсутствие в стандартах пояснений о подходах к их правильной интерпретации, особенно в тех случаях, когда о чем-то умалчивают. В известной степени это даже философский вопрос, в духе лингвистического поворота и литературоведения.

cher-nov 17.09.2023 22:41
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
4
10
223
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Стандарт C89/C90 был написан для описания семейства диалектов, которые уже использовались, некоторые из которых определяли поведение в обстоятельствах, в которых другие не были. Вместо того, чтобы пытаться полностью описать все необходимое, чтобы сделать язык пригодным для какой-либо конкретной цели, которой служат эти диалекты, Стандарт ограничился аспектами, которые были общими для всех диалектов C.

Когда был написан Стандарт, существовал значительный корпус программ, написанных для реализаций, которые обрабатывали определенные конструкции «документированным образом, характерным для среды», ориентированными на среды, которые документировали поведение конструкций каким-то полезным способом, в то же время время, поскольку были реализации, написанные для других платформ, которые не определяли такое поведение. Вместо того, чтобы требовать, чтобы все реализации имитировали обычное поведение или чтобы все соответствующие программы преодолевали препятствия, чтобы учесть ограничения нескольких неясных реализаций, Стандарт просто отказался от юрисдикции, исходя из презумпции, что люди, стремящиеся продать реализации, предпримут добросовестные усилия. чтобы сделать их полезными для своих клиентов.

Согласно обоснованию C99 (хотя принцип не изменился со времен C89/C90; выделен оригинал):

Термины «неопределённое поведение», «неопределённое поведение» и «поведение, определяемое реализацией» используются для классификации результатов написания программ, свойства которых Стандарт не описывает или не может полностью описать. Целью принятия этой категоризации является обеспечение определенного разнообразия среди реализаций, которое позволяет качеству реализации быть активной силой на рынке, а также разрешить определенные популярные расширения, не удаляя при этом печать соответствия Стандарту. В информативном приложении J стандарта перечислены модели поведения, которые попадают в одну из этих трех категорий.

Обратите внимание: тот факт, что один компилятор обрабатывает конструкцию, определяемую реализацией, способом, отличным от другого, на самом деле не будет выглядеть как «расширение», как и тот факт, что, например, реализация определяет порядок, в котором будут оцениваться аргументы функции. Однако тот факт, что реализация будет обрабатывать некоторую конструкцию, над которой Стандарт отказывается от юрисдикции, «документированным образом, характерным для среды», значительно расширит семантику, доступную программисту, который использовал эту реализацию и понимал рассматриваемую среду.

Ответ принят как подходящий

Как стандарты C и C++ предписывают вам действовать в ситуациях, которые ими не охвачены?

Спецификации языка объясняют, как ведут себя соответствующие реализации соответствующих языков. Они ничего не говорят о том, как вам следует себя вести.


  1. Как обрабатывать недоопределенное поведение, которое явно не указано как определяемое реализацией, неуказанное или даже неопределенный?

В спецификации не обязательно явно указывать, что поведение не определено. C, в частности, определяет «неопределённое поведение» следующим образом:

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

(С17 3.4.3/1).

Все версии спецификации языка C имеют такую ​​или очень похожую формулировку, и я почти уверен, что то же самое относится и к C++.

Что касается того, как с этим бороться, то безопаснее всего его избегать. Или для «неопределенного» или «определяемого реализацией» поведения вы можете безопасно игнорировать его, если все альтернативы, разрешенные спецификацией, приемлемы для вас.

В качестве альтернативы, если вы специально нацелены на реализацию, которая определяет рассматриваемое поведение (независимо от того, делает ли соответствующая спецификация «определенной реализацией»), и вас не беспокоит переносимость на другие реализации, тогда вы можете положиться на документацию вашей реализации. .


  1. Следует ли использовать в таких случаях новые стандарты?

Нет смысла полагаться на документацию, которая не относится к той реализации, которую вы фактически используете. Небезопасно и неразумно предполагать, что поведение, определенное только более поздней версией спецификации, будет проявляться реализациями (только) более ранней версии спецификации.

Однако вы можете рассмотреть возможность перехода на реализацию более поздней спецификации. См. также выше.


  1. Следует ли подавать отчет о дефектах для отмененного стандарта?

Кажется, это вряд ли будет полезно. Вы должны понимать, что отзыв (версии) стандарта означает, что он больше не будет поддерживаться.

В случае со спецификациями языков C и C++, если ваша проблема решена в более поздней версии спецификации, комитет наверняка посчитает, что она решена адекватно. Если нет, то вы можете рассмотреть возможность подачи DR для текущей версии, понимая, что любое исправление будет нацелено на эту или будущую версию спецификации.

Спецификации языка объясняют, как ведут себя соответствующие реализации соответствующих языков. Они ничего не говорят о том, как вам следует себя вести. - Определенно, но сами реализации не субъективны; они также написаны программистами-людьми. Это то, что я имел в виду.

cher-nov 16.09.2023 19:25

В спецификации не обязательно явно указывать, что поведение не определено. C, в частности, определяет «неопределённое поведение» следующим образом: <...> — Согласен, но я скорее имел в виду поведение, которое не должно быть неопределённым ни при каких обстоятельствах, потому что в противном случае это сделало бы язык частично несогласованным. Другими словами, это проблемы, по которым стоит подать отчет о дефекте, если затронутый стандарт все еще действует.

cher-nov 16.09.2023 19:25

@cher-nov Я думаю, что лучшим примером того, что вы имеете в виду, было бы прямое внутреннее противоречие в стандарте, который для C++ определенно существует, и я был бы удивлен, если бы его не существовало в C. Например, из текущего стандарта C++ вы можете сделать вывод что соответствующая реализация должна завершать следующую программу кодом выхода 0: struct A{};struct B:A{};struct C:A{B b;};C c;int main(){return (A*)&c == (A*)&c.b;}; Но вы также можете сделать вывод, что она должна заканчиваться кодом выхода 1.

user17732522 16.09.2023 19:53

@cher-nov: Ситуации, когда стандарт C можно интерпретировать как требование реализации для обработки программы в одном направлении, и где его можно интерпретировать как запрещающий такое поведение, редки. Однако ситуации, когда его можно интерпретировать как указание поведения программы, но также и указание, что оно эквивалентно некоторой другой конструкции, в отношении которой она отказывается от юрисдикции, являются обычными и представляют собой только противоречие отказа от юрисдикции, интерпретируются как запрет.

supercat 17.09.2023 18:20

@cher-nov, «сами реализации не субъективны; они также написаны программистами-людьми. Вот что я имел в виду». -- Я не вижу различия, которое вы пытаетесь провести. Спецификации также не говорят разработчикам языка, что делать. Скорее они предоставляют стандарт, по которому можно оценивать работу разработчиков: либо «это соответствующая реализация C (или C++)», либо нет. И поскольку вы утверждаете, что разработчики могут не чувствовать себя обязанными предоставлять соответствующую реализацию, я не вижу пути оттуда к спецификации, указывающей кому-либо, что делать.

John Bollinger 17.09.2023 21:39

@cher-nov, относительно «поведения, которое не должно быть неопределенным ни при каких обстоятельствах, потому что в противном случае это сделало бы язык частично несовместимым» - если спецификация оставляет данное поведение неопределенным, то это не может вызвать какое-либо несоответствие в языке, как он определен. Как может спецификация, не предъявляющая никаких требований, сделать что-то противоречивым? И поскольку вы конкретно спрашиваете о поведении, которое явно не объявлено неопределенным (или не определено или не указано в реализации), не может быть даже противоречия относительно того, является ли оно на самом деле неопределенным.

John Bollinger 17.09.2023 21:50

Другие вопросы по теме

Есть ли способ напечатать n-битное (например, 256-битное) целое число в c без использования внешней библиотеки?
Ошибка при внесении изменений с помощью динамического программирования в c
Безопасно ли изменять данные с помощью указателя, когда их наблюдает другой указатель на константу?
Указатель на член возвращаемой структуры, безопасно ли это?
Дочернее окно отправляет сообщение WM_COMMAND неожиданному родителю при нажатии клавиши Enter, когда оно находится в фокусе
Невозможно назначить строковые литералы массиву символов в C
Execve не выдает вывод с помощью команды «который»
Ошибка компиляции Xcode 15: импорт модуля C++ «zlib» появляется в спецификации внешней связи языка «C»
Функция удаления не работает, пока я не добавлю оператор if с истиной и ложью
Возникли проблемы с поиском ошибки в моем коде для проблемы CS50x, установите 4 «фильтр-больше» для функции «Края»