Почему я могу неявно преобразовывать int-литерал в int * в C, но не в С++?
Я полагал, что в следующем коде C автоматически отбрасывает 17 на int *
, что, как недавно указывал кто-то (но не объяснял причины), ошибочно.
int *ptoi = 17; // I assumed that 17 is being automatically casted to int *
Я знаю, что если я делаю то же самое, что и выше в С++, я получаю сообщение об ошибке invalid conversion from int to int *
. Но если я делаю следующее в С++, он отлично работает:
int *ptoi = (int *)17;
Вот причины, по которым я думал, что в C кастинг был неявным.
Может ли кто-нибудь объяснить, почему, на С++, я должен использовать его, но на C он отлично работает?
Ответы
Ответ 1
Преобразования из целых чисел в указатели без приведения также являются незаконными в C. Большинство компиляторов позволят вам уйти от него, хотя. Кланг дает предупреждение:
example.c:5:8: warning: incompatible integer to pointer conversion initializing
'int *' with an expression of type 'int'
int *x = 17;
^ ~~
C99 говорит в Раздел 6.5.4 Операторы роли, пункт 4:
Конверсии, которые включают указатели, кроме случаев, когда это разрешено ограничениями 6.5.16.1, должны быть указаны с помощью явного приведения.
6.5.16.1 является исключением для void *
преобразования в другие указатели без необходимости приведения.
Спецификация С++ говорит в Раздел 5.4 Явное преобразование типа (литая нотация), пункт 3:
Преобразование любого типа, не упомянутое ниже и явно не определяемое пользователем, плохо сформировано.
Итак, вы идете - незаконно на обоих языках, но для совместимости с большим количеством старого программного обеспечения многие компиляторы C позволят вам с ним справиться.
Ответ 2
Да, кастинг подразумевается на C, хотя многие (все?) компиляторы дают предупреждение. В С++ неявное преобразование выполняется от int
до int*
, поэтому требуется явное литье.
Ответ 3
Было, C имеет неявные преобразования - по моему опыту в значительной степени от любого интегрального типа к любому другому интегральному типу. Указатели в C являются <забастовочными > считаются интегральными типами scalar
.
В С++ интегральные типы определяются следующим образом:
Типы bool
, char
, char16_t
, char32_t
, wchar_t
и целые типы signed
и unsigned
являются коллективными называемые интегральными типами. 48 Синоним интегрального типа является целым типом. Представления интегральных типов должен определять значения с использованием чистой двоичной системы нумерации. 49 [Пример: этот международный стандарт позволяет дополнять 2s, 1s дополнять и подписывать представления величин для интегральных типов. -конец пример]
Единственное целочисленное значение, которое может быть преобразовано в тип указателя в С++, является константой нулевого указателя, хотя технически преобразование относится к prvalue
типа std::nullptr_t
. (пункт 4.10)
Заключительная записка
Вместо того, чтобы фиксировать его так:
int *ptoi = (int *)17;
с учетом добавления стилей в стиле С++:
int *ptoi = reinterpret_cast<int*>(17);
чтобы понять, какое преобразование вы пытаетесь вызвать
Ответ 4
Компилятор интерпретирует int *ptoi = 17;
как переменную ptoi, которая указывает на целое число в местоположении 17 (0x00000011).
C - просто совершенно другой язык. Это может выглядеть как С++, но это не так. Для обоих языков применяются разные правила.
Я должен, вероятно, указать, что как C, так и С++ будут (насколько мне известно) сделать его указателем на 0x00000011, но C просто жалуется на меньшее, поскольку назначение ячеек памяти является недействительным в C.