Подтвердить что ты не робот

Почему я могу неявно преобразовывать 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 он отлично работает?

4b9b3361

Ответ 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.