Мы знаем в общем sizeof(long) != sizeof(int)
, Но какие части стандарта (C ++ 11) запрещают использование псевдонимов long*
через int*
? Является ли это просто упущением в [conv.ptr], правилами наложения имен в [basic.lval] или чем-то еще?
void f()
{
static_assert(sizeof(int) == sizeof(long), "");
long x[] = {1, 2};
int* y = x; // error: invalid conversion from ‘long int*’ to ‘int*’ [-fpermissive]
}
Да, это бездействие в [conv.ptr]
и соответствующий пункт в [expr.reinterpret.cast]
,
7
Указатель объекта может быть явно преобразован в указатель объекта
другой тип. Когда значение v типа «указатель на T1»
преобразован в тип «указатель на cv T2», результат
static_cast<cv T2*>(static_cast<cv void*>(v))
если оба T1 и T2
Типы стандартного макета (3.9) и требования выравнивания T2
не более строгие, чем у T1, или если любой из типов является недействительным. Преобразование
prvalue типа «указатель на T1» на тип «указатель на T2» (где T1
и T2 являются типами объектов, и где требования выравнивания T2
не более строгие, чем у T1), и обратно в исходный тип дает
исходное значение указателя. Результат любого другого такого указателя
конверсия не указана.
Вы должны использовать reinterpret_cast<int*>(...)
,
РЕДАКТИРОВАТЬ. В комментариях есть беспокойство, которое я делаю более заметным в этом редакторе, что это не вопрос языка-юриста, а намерение использовать указатель. Я не уверен, как возникла проблема, так как довольно очевидно, что можно просто C-cast без вопросов, но если есть сомнения — указатель приведен к int*
нарушает строгое наложение правила.
То есть неопределенное поведение может возникать из-за того, что вы нарушаете предположение компилятора о том, что указатели разных типов никогда не могут указывать на одну и ту же область памяти.
long
а также int
два разных типа, даже если они имеют одинаковый размер, поэтому я думаю, что неправильное преобразование связано с [basic.lval.10]
Если программа пытается получить доступ к сохраненному значению объекта через
поведение, отличное от одного из следующих типов поведения
не определено:
- динамический тип объекта,
- cv-квалифицированная версия динамического типа объекта,
- тип, подобный (как определено в 4.4) динамическому типу объекта,
- тип, который является типом со знаком или без знака, соответствующим динамическому типу
объект,- тип, который является типом со знаком или без знака, соответствующим cv-квалифицированной версии динамического типа объекта,
- агрегатный или объединенный тип, который включает в себя один из вышеупомянутых типов
среди его элементов или нестатических членов данных (в том числе,
рекурсивно, элемент или нестатический член данных субагрегата или
содержавший союз),- тип, который является (возможно, квалифицированным cv) типом базового класса динамического типа объекта,
- тип char или unsigned char.
Как примечание стороны, если [basic.lval] не существовало, были бы другие проблемы: один и тот же размер не означает одинаковое представление / диапазон.
Там нет никакой гарантии, что значение битов в int
точно соответствуют значениям битов в long
,