Возьмите следующий код
#include <iostream>
void func() {
int i = 2147483640;
while (i < i + 1)
{
std::cerr << i << '\n';
++i;
}
return;
}
int main() {
func();
}
Этот код явно неверен, так как цикл while может завершиться только в случае переполнения подписанного int i
, которым является UB, и, следовательно, компилятор может, например, оптимизировать его до бесконечного цикла (который Clang делает на -O3
) или выполнять другие виды фанк вещи. Теперь мой вопрос: из моего чтения стандарта C ++ типы, которые эквивалентны псевдониму может со знаком (т.е. указатели int*
и unsigned*
могут быть псевдонимом). Имеет ли следующее поведение undefined или нет, чтобы сделать некую фанковую подписанную упаковку?
#include <iostream>
static int safe_inc(int a)
{
++reinterpret_cast<unsigned&>(a);
return a;
}
void func() {
int i = 2147483640;
while (i < safe_inc(i))
{
std::cerr << i << '\n';
++i;
}
return;
}
int main() {
func();
}
Я пробовал приведенный выше код с Clang 8 и GCC 9 на -O3
с -Wall -Wextra -Wpedantic -O3 -fsanitize=address,undefined
аргументами и не получил ошибок или предупреждений, и цикл завершился после переноса на INT_MIN
.
cppreference.com сообщает мне, что
Псевдонимы типов
Всякий раз, когда делается попытка прочитать или изменить сохраненное значение объекта типа DynamicType через glvalue типа AliasedType, поведение не определено, если не выполняется одно из следующих условий:
- AliasedType - это (возможно, cv-квалифицированный) вариант DynamicType со знаком или без знака.
что, по моему мнению, означает, что для целей псевдонима типов подписи не учитываются, а код, использующий reinterpret_cast
, имеет четко определенную семантику (хотя в любом случае он несколько дрянный).
reinterpret_cast<unsigned&>(x)
? Разве+reinterpret_cast<unsigned&>(x)
не должно быть значениемx
? Где использование reinterpred_casted ptr / lvalue определяется как переинтерпретация представления объекта? 25.05.2019