Почему эта программа, которая выполняет неверную инициализацию указателя, прекрасно компилируется в C?
Я написал простую программу на C и ожидал, что она не удастся компилировать, но, к сожалению, она компилируется и работает нормально в C, но не компилируется в C++. Рассмотрим ниже программу:
#include <stdio.h>
int main()
{
char *c=333;
int *i=333;
long *l=333;
float *f=333;
double *d=333;
printf("c = %u, c+1 = %u",c,c+1);
return 0;
}
Посетите эту ссылку: http://ideone.com/vnKZnx
Я думаю, что эта программа определенно не может компилироваться в C++ из-за строгой проверки типов в C++. Почему эта программа компилируется в C? Это факт, что компилятор также показывает предупреждения. Я использую Orwell Dev C++ IDE(компилятор gcc 4.8.1). Я также попробовал ту же программу на другом компиляторе (Borland Turbo C++ 4.5), сохранил его с расширением.c и на этом компиляторе он не смог скомпилироваться.
3 ответа
Этот код не является ни легальным C, ни легальным C++.
N1570 §6.7.9 / p11:
Инициализатор для скаляра должен быть одним выражением, необязательно заключенным в фигурные скобки. Начальное значение объекта - это значение выражения (после преобразования); применяются те же ограничения и преобразования типов, что и для простого присваивания, принимая тип скаляра за неквалифицированную версию его объявленного типа.
§6.5.16.1 / p1 предусматривает, что для простого присвоения:
Одно из следующего должно иметь место:
- левый операнд имеет атомарный, квалифицированный или неквалифицированный арифметический тип, а правый имеет арифметический тип;
- левый операнд имеет атомарную, квалифицированную или неквалифицированную версию структуры или типа объединения, совместимого с типом правого;
- левый операнд имеет атомарный, квалифицированный или неквалифицированный тип указателя, и (учитывая тип, который левый операнд будет иметь после преобразования в lvalue) оба операнда являются указателями на квалифицированные или неквалифицированные версии совместимых типов, а тип, на который указывает левый, имеет все классификаторы типа, на который указывает право;
- левый операнд имеет атомарный, квалифицированный или неквалифицированный тип указателя, и (учитывая тип, который будет иметь левый операнд после преобразования в lvalue), один операнд является указателем на тип объекта, а другой - указателем на квалифицированную или неквалифицированную версию
void
и тип, на который указывает левый, имеет все квалификаторы типа, на который указывает правый;- левый операнд является атомарным, квалифицированным или неквалифицированным указателем, а правый - константой нулевого указателя; или же
- левый операнд имеет тип атомарный, квалифицированный или неквалифицированный
_Bool
, а справа указатель.
Ни один из которых не соответствует указателю слева и 333
справа. §6.5.16.1/p1 является ограничением, и для реализации диагностики при нарушении ограничения требуются соответствующие реализации (§5.1.1.3/p1):
Соответствующая реализация должна генерировать по крайней мере одно диагностическое сообщение (идентифицированное определенным реализацией способом), если блок преобразования или блок предварительной обработки содержит нарушение какого-либо синтаксического правила или ограничения, даже если поведение также явно указано как неопределенное или как реализация. определены.
Бывает, что GCC решает выдать предупреждение вместо ошибки в режиме C и продолжает его компилировать, но это не обязательно.
C может конвертировать числа в указатели. char* c = 123
установит c
указать на 123-й байт в памяти.
Хотя это почти бесполезно и почти наверняка является ошибкой в программировании на рабочем столе, во встроенных системах необходимо взаимодействовать с аппаратным обеспечением, которое может искать значения в определенных, жестко закодированных адресах памяти.
Этнически нет ничего плохого в вашем коде. Вы инициализируете указатели с целочисленными значениями констант 333. и затем печатаете адрес. Это предупреждение, вероятно, связано с тем, что целочисленное значение является типом, приведенным к типу адреса.
проблема начнется, когда вы попытаетесь разыменовать указатели. Это даст ошибку сегментации.