С++. Какое раннее поведение undefined может проявиться?
Я знаю, что поведение undefined может потенциально вызвать что-либо, что делает любую программу, содержащую UB, бессмысленной. Мне было интересно, есть ли способ идентифицировать самый ранний момент в программе, поведение undefined может вызвать проблемы.
Вот пример, чтобы проиллюстрировать мой вопрос.
void causeUndefinedBehavior()
{
//any code that causes undefined behavior
//every time it is run
char* a = nullptr;
*a;
}
int main()
{
//code before call
//...
causeUndefinedBehavior();
//code after call
//...
}
По моему мнению, возможное поведение undefined может быть вызвано (не обязательно проявляется):
- Когда
causeUndefinedBehavior()
скомпилирован.
- Когда
main()
скомпилирован.
- Во время запуска программы.
- В момент выполнения
causeUndefinedBehavior()
.
Или точка, в которой поведение undefined вызвано совершенно другим для каждого случая и каждой реализации?
Кроме того, если я прокомментировал строку, в которой вызывается causeUndefinedBehavior()
, это устранит UB, или он все еще будет в программе, поскольку скомпилирован код, содержащий UB?
Ответы
Ответ 1
Как ваш код несколько демонстрирует, поведение undefined почти всегда является условием состояния выполнения во время попытки поведения. Небольшая модификация вашего кода может сделать это болезненно очевидным:
void causeUndefinedBehavior()
{
//any code that causes undefined behavior
//every time it is run
char* a = nullptr;
*a;
}
int main()
{
srand(time(NULL));
//code before call
//...
if (rand() % 973 == 0)
causeUndefinedBehavior();
//code after call
//...
}
Вы можете выполнить это тысячу раз или больше и никогда не запускать условие выполнения UB. что не изменяет тот факт, что сама функция явно UB, но обнаружение ее во время компиляции в контексте invoker не является тривиальным.
Ответ 2
Я думаю, что это зависит от типа поведения undefined. Вещи, которые повлияли бы на что-то вроде смещения структуры, могут привести к поведению undefined, которое будет отображать любой временной код, который затрагивает эту структуру.
Однако в большинстве случаев поведение undefined происходит в время выполнения, что означает, что только если этот код будет выполнен, произойдет поведение undefined.
Например,, попытка изменить строковый литерал имеет поведение undefined:
char* str = "StackOverflow";
memcpy(str+5, "Exchange", 8); // undefined behavior
Это "undefined поведение" не будет выполняться до выполнения memcpy
. Он по-прежнему будет компилироваться в совершенно нормальный код.
Другим примером является исключение возврата из функции с невоидным возвращаемым типом:
int foo() {
// no return statement -> undefined behavior.
}
Здесь он находится в точке, где foo
возвращает, что происходит поведение undefined. (В этом случае на x86 все, что попадало в регистр eax
, - это возвращаемое возвращаемое значение функции.)
Многие из этих сценариев можно идентифицировать, включив более высокий уровень сообщений об ошибках компилятора (например, -Wall
в GCC.)
Ответ 3
"Undefined поведение" означает, что определение языка не говорит вам, что будет делать ваша программа. Это очень простое утверждение: никакой информации. Вы можете расспрашивать все, что вам нравится, о том, что ваша реализация может или не может сделать, но если ваша реализация не документирует то, что она делает, вы только догадываетесь. Программирование не связано с угадыванием; это о знании. Если поведение вашей программы undefined, исправьте ее.
Ответ 4
в то время как это "поведение w90 > ", учитывая конкретный компилятор, он будет иметь предсказуемое поведение. Но поскольку это undefined, на разных компиляторах, это может привести к тому, что поведение происходит в любой точке процесса компиляции/выполнения
Ответ 5
что делает любую программу, содержащую UB, потенциально бессмысленной
Не совсем верно. Программа не может "содержать" UB; когда мы говорим "UB", что коротко: поведение программы undefined. Все это!
Таким образом, программа не просто потенциально, а фактически бессмысленна с самого начала.
[intro.execution]/5
: Соответствующая реализация, выполняющая хорошо сформированную программу, должна обеспечивать такое же наблюдаемое поведение, как и одно из возможных исполнений соответствующего экземпляра абстрактной машины с той же программой и тем же входом. Однако, если какое-либо такое исполнение содержит операцию undefined, , этот международный стандарт не устанавливает требования к реализации, выполняющей эту программу с этим вводом (даже в отношении операций, предшествующих первой операции undefined),.