Понимание области неопределенного поведения

Каким образом стандарт C++ ограничивает влияние неопределенного поведения, если таковое имеется? Например, в приведенном ниже коде от первого if, проверяющего undefined, поток управления ограничен следующим образом: путь then или путь else? Можно ли пропускать оба пути? Выполнить оба пути (потенциально параллельно)? Совершить безумный прыжок в середину второго if?

void f(int undefined) {
    bool startNuclearWar = true;

    if (undefined > 0) {
        printf("True path\n");
        startNuclearWar = false;
    } else {
        printf("False path\n");
        startNuclearWar = false;
    }

    if (startNuclearWar) {
        lauchMissles();
    }
}

Ни в коем случае.

n. 'pronouns' m. 22.03.2018 19:01

Возможный дубликат Неопределенное поведение и точки последовательности

WorldSEnder 22.03.2018 19:57
Стоит ли изучать 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 называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
2
83
3

Ответы 3

Стандарт не имеет ограничений на UB. В тот момент, когда вы выполняете что-нибудь, который вызывает UB, стандарт ничего не гарантирует относительно того, что происходит.

Фактически, UB вступает в силу с момента, когда внешний ввод устанавливает программу на пути к чему-то, что в конечном итоге вызовет неопределенное поведение.

Sebastian Redl 22.03.2018 20:42

@SebastianRedl - неправда. UB может быть результатом ввода (например, ввод пользователя приводит к переполнению int в каком-либо последующем операторе), но это не означает, что UB вступает в силу с момента ввода. Ввод может повлиять на то, будет ли достигнут оператор с UB, но - до тех пор, пока какой-либо оператор не будет отображать UB, поведение каждого предыдущего оператора четко определено.

Peter 23.03.2018 10:14

@Peter: N4727 [intro.abstract] p5: «Однако, если любое такое выполнение содержит неопределенную операцию, этот документ не налагает никаких требований на реализацию, выполняющую эту программу с этим входом (даже в отношении операций, предшествующих первой неопределенной операции)». UB работает в обратном направлении.

Sebastian Redl 23.03.2018 10:32

Хотя есть много ситуаций, когда было бы полезно иметь возможность «разделить» неопределенное поведение, и хотя это было бы недорого на многих платформах, люди, пишущие Стандарты, не проявили к этому особого интереса. Стандарт C11 предлагает Приложение L о «анализируемости», но не описывает ничего значимого, что реализация должна гарантировать, если определяет __STDC_ANALYZABLE__.

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

 int index = computeSomething();
 if (index < 0 || index >= ARRAYSIZE) FatalError();
 myArray[index]++;

будет использовать одно и то же значение для index при сравнении и поиске в массиве.

Многие реализации могут дешево предлагать множество полезных гарантий, помимо тех, которые требуются стандартом, особенно в областях приложения, где для программы было бы допустимо аварийное завершение при получении недопустимого ввода, но неприемлемо для нее позволить злонамеренно сконструированному вводу взять под контроль машина. К сожалению, в Стандарте не предусмотрены необходимые ловушки для эффективного использования этого преимущества (например, предоставление встроенной функции, которая могла бы принимать значение, которое может быть неопределенным, и выдавать значение, которое в худшем случае является неопределенным). Применение такой внутренней функции к значению в index в приведенном выше коде перед выполнением сравнения гарантирует, что даже в случае переполнения в computeSomething код гарантированно либо увеличит значение в массиве, либо заметит, что index недействителен. Поскольку ни одна операция не приведет к критическому неопределенному поведению, выполнение останется на рельсах.

In what way(s), if any, does the C++ standard limit the effect of undefined behavior?

Никак нет. Неопределенное поведение по своей природе является неопределенный, поэтому может произойти абсолютно что-нибудь. И как только что-то произошло неопределенный, с этого момента состояние программы будет неизвестный.

При этом в показанном вами коде нет неопределенного поведения. Все в коде имеет определенное поведение.

For instance, in the code below, from the first if inspecting undefined is control flow constrained to follow either the then path or the else path?

Да.

Is it allowed to skip both paths?

Нет.

Execute both paths (potentially in parallel)?

Нет.

Take a wild jump into the middle of the second if?

Нет.

Если в каком-либо ранее выполненном коде возникло неопределенное поведение, то ответы на вопросы будут прямо противоположны тому, что дал yoi. ;-)

Peter 22.03.2018 20:41

Фактически, состояние программы неизвестно назад во времени, чтобы учесть переупорядочение оптимизаций и других модификаций.

Sebastian Redl 22.03.2018 20:41

@Peter: даже если бы UB действительно возник, я бы не ожидал, что языковые конструкции, такие как if, перестанут работать так, как они определены для работы. Однако UB может повлиять на данные, с которым они работают. Если только UB не уничтожает память, которая содержит исполняемый код if.

Remy Lebeau 22.03.2018 20:54

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