#c #visual-c
#c #visual-c
Вопрос:
Почему мой static_cast указателя терпит неудачу?
int iDog = 456;
int *piDog = amp;iDog;
long *plDog = static_cast<long*>(piDog); // invalid type conversion
long lDog = static_cast<long>(iDog); // ok
long* plDog = (long*)(piDog); // this is OK too... very weird!! (Dynamic cast... and we aren't allowed to use this one in our coding standards)
Эта ссылка предполагает, что все должно быть в порядке: https://en.cppreference.com/w/cpp/language/static_cast
Проблема с Visual Studio C ?
Комментарии:
1. Подсказка:
sizeof(long) != sizeof(int)
.piDog
недостаточно велик, чтобы вместитьlong
.2. Что касается стандарта, я не думаю, что это действительно имеет значение, если они одинакового размера, это все равно неправильно.
3. Как эта ссылка предполагает, что все в порядке? Удивительно, что вы думаете, что Visual Studio неправильно поняла бы такой тривиальный фрагмент кода. Используйте
reinterpret_cast
вместо этого.4. Ссылка, на которую вы ссылаетесь, содержит 10 точек, указывающих разрешенные приведения. Это оставляет читателю много догадок. Возможно, вы могли бы отредактировать свой вопрос и добавить объяснение того, какой пункт, по вашему мнению, применим и почему он применим?
5.
(long*)
это кастинг Молотом Божьим. Независимо от того, насколько плохим, глупым или безумным является преобразование, приведение в стиле C сделает это возможным. Мое эмпирическое правило, когда я вижу одного из этих детей, — более внимательно изучить код на предмет ошибки, которую он скрывает.
Ответ №1:
long *plDog = static_cast<long*>(piDog); // invalid type conversion
Почему мой static_cast указателя терпит неудачу?
Потому что он неправильно сформирован. Ни одно из правил static_cast не применяется к приведению, которое вы пытаетесь выполнить. Это недопустимое преобразование, как вы упоминаете в комментариях.
Указатель на один тип объекта не может быть статически преобразован в указатель на другой тип объекта, если они не являются указателями на связанные классы или при приведении к / из указателя на void .
Эта ссылка предполагает, что все должно быть в порядке: https://en.cppreference.com/w/cpp/language/static_cast
Эта ссылка предполагает, что преобразование, которое вы пытаетесь выполнить, не в порядке.
long* plDog = (long*)(piDog); // this is OK too... very weird!!
Это правильно сформированное преобразование. Это не «странно».
Существует много преобразований, которые разрешают явные преобразования (также называемые «приведение нотации» или «приведение в стиле C»), а статические приведения не разрешают. Это потому, что статические приведения имеют (по крайней мере, видимость) безопасности типов, в то время как явные преобразования по существу просят компилятор притвориться, что система типов не существует.
Обратите внимание, что косвенное plDog
обращение к объекту и доступ к нему приведут к неопределенному поведению. Как вы можете видеть, хорошо, что вы получили сообщение об ошибке.
и нам не разрешено использовать это в наших стандартах кодирования
Это хорошее ограничение. Вашей команде будет немного сложнее писать ошибки, ошибочно обходя систему типов.
Проблема с Visual Studio C ?
Нет, проблема в том, что программа плохо сформирована. Компилятор правильно информирует вас об ошибке и не требуется для компиляции программы.
Я рекомендую спросить себя: почему вы хотите или думаете, что вам нужно выполнить такое приведение?
Ответ №2:
TL; DR: Если бы ваше приведение работало, язык не давал бы никаких гарантий безопасности типов для указателей, и это ключевая часть мотивации для введения приведений в стиле C вместо того, чтобы придерживаться приведения старой школы C.
На языке стандарта C / C long*
и int*
не являются «совместимыми с указателями». Вы не можете неявно преобразовать a long*
в an int*
или наоборот, поэтому static_cast
не можете сделать это за один раз.
Причина этого
sizeof(long)
не всегда одинаковаsizeof(int)
для всех платформ. Это разные фундаментальные типы. Это верно в целом для всех различных типов C / C , даже если они имеют идентичную двоичную компоновку. Они только «совместимы с указателями», если в синтаксисе языка вы объявляете типы, которые должны быть связаны с помощью неявного преобразования.
Вы можете использовать static_cast
при преобразовании из a void*
в любой указатель на тип объекта или наоборот.
Поэтому вы можете сделать это двумя способами:
reinterpret_cast<long*>(piDog);
-или-
static_cast<long*>(static_cast<void*>(piDog));
Стилистически использование reinterpret_cast
намного понятнее. В любом случае достоверность приведения зависит от архитектуры и предполагает sizeof(int)
== sizeof(long)
, а также одинаковое расположение памяти.
IOW Это безопасно для Windows x86 и x64 native, но может быть недоступно для других платформ или процессоров. Это одна из причин, по которой Windows x64 предпочитает использовать модель данных LLP64, как описано в этом сообщении в блоге.
Смотрите cppreference для static_cast и reinterpret_cast
Комментарии:
1. Имеют ли они одинаковый размер или нет
int
,long
не имеет значения; типы не связаны (один не является производным от другого), и astatic_cast
не допускается между указателями на несвязанные типы.2. Уверен, что они не являются «совместимыми с указателями» на языке стандарта. Я пытался обратиться к комментарию OP «Но они оба типа указателей и (обычно) sizeof(long *) == sizeof(int *) «.
3. Первый ответ был немного грубым, поэтому я попытался его немного почистить…
4.Meh. Я думаю, вы упустили момент, который заключается в том, что OP пытается использовать указатели, а не простые
int
иlong
типы данных. Вы моглиtypedef
бы использовать два идентичныхstruct
типа, и все равно расстояниеstatic_cast
между их указателями было бы недействительным