Идея "[...] делает указатель из целого числа без приведения" - PullRequest
0 голосов
/ 19 февраля 2019

Мне всегда было интересно, почему предупреждения passing argument 1 from of 'foo' makes pointer from integer without a cast и тому подобное являются только предупреждениями, а не ошибками.

На самом деле эти предупреждения почти всегда являются ошибками.

Кто-нибудь знает, в чем суть этого?

  • Предназначено ли это для того, чтобы доисторический код компилировался без ошибок?
  • Или просто для соответствия стандарту?Тогда последний, возможно, нуждается в некотором исправлении.

Пример:

int foo(int *bar)
{
  *bar = 42;
}

void bar()
{
  int n = 0;
  foo(n);      // this is obviously an error
  ...
}

Ответы [ 3 ]

0 голосов
/ 19 февраля 2019

Per 6.5.2.2 Вызовы функций , ¶ 7:

Если выражение, обозначающее вызываемую функцию, имеет тип, который включает в себя прототип, аргументы неявно преобразуютсякак при присваивании типам соответствующих параметров, принимая тип каждого параметра за неквалифицированную версию его объявленного типа

Соответствующий текст в 6.5.16.1 Простое назначение is:

Ограничения

Должно выполняться одно из следующих значений:

  • левый операнд имеет атомарный, квалифицированный или неквалифицированный арифметический тип,а правый имеет арифметический тип;
  • левый операнд имеет атомарный, квалифицированный или неквалифицированный вариант структуры или типа объединения, совместимый с типом правого;
  • левый операнд имеет атомарныйуказатель, квалифицированный или неквалифицированный тип указателя и (учитывая тип, который левый операнд будет иметь после преобразования lvalue) оба операнда являются указателями на квалифицированный или неквалифицированныйd версии совместимых типов, а тип, на который указывает левый, имеет все квалификаторы типа, на который указывает правый;
  • левый операнд имеет атомный, квалифицированный или неквалифицированный тип указателя и (с учетомвведите левый операнд после преобразования в lvalue) один операнд - указатель на тип объекта, а другой - указатель на квалифицированную или неквалифицированную версию void, а тип, на который указывает левый, имеет все квалификаторы типауказывает справа;
  • левый операнд является атомарным, квалифицированным или неквалифицированным указателем, а правый - константой нулевого указателя;или
  • левый операнд имеет тип атомарный, квалифицированный или неквалифицированный _Bool, а правый - указатель.

Ни один из них не допускает использование левого операнда в качестве указателя иправильный операнд как целое число.Таким образом, такое присваивание (и в первом приведенном выше тексте вызов функции) является нарушением ограничения .Это означает, что стандарт требует, чтобы компилятор «диагностировал» его.Однако это зависит от компилятора, что он делает дальше.Да, ошибка была бы крайне предпочтительной, но простая печать предупреждения - это некачественный способ удовлетворить требование «диагностировать» нарушения ограничений, подобные этому.

0 голосов
/ 20 февраля 2019

Кто-нибудь знает, в чем суть этой идеи?

  • В основном это позволяет компилировать доисторический код без ошибок?
  • Или просто для соответствия стандарту?Тогда последний, возможно, нуждается в некотором исправлении.

Это соответствует стандарту в том смысле, что стандарт требует соответствующих реализаций для диагностики таких проблем, как @R .. описывает в своем ответе.Однако реализации не необходимы для отклонения программ из-за таких проблем.Что касается того, почему некоторые компиляторы вместо этого принимают такие программы, это нужно будет оценивать для каждой конкретной реализации, но эта цитата из первого издания K & R может пролить немного света:

5.6 Указатели не являются целыми числами

В более старых программах на Си вы можете заметить довольно резкое отношение к копированию указателей.Обычно верно, что на большинстве машин указатель может быть назначен целому числу и обратно;не происходит масштабирование или преобразование, и биты не теряются.К сожалению, это привело к лишению свободы с подпрограммами, которые возвращают указатели, которые затем просто передаются другим подпрограммам - требуемые объявления указателей часто пропускаются.

(Kernighan & Ritchie, * 1023)* Язык программирования C , 1 st ed., 1978)

Во-первых, обратите внимание, что это долго предшествует даже C89.Сегодня я немного удивлен, что авторы , а затем говорили о "старых" программах на Си.Но учтите также, что даже в то время язык C, определенный K & R, формально не разрешал неявное преобразование между указателями и целыми числами (хотя он допускал приведение между ними). ​​

Тем не менее, были программы, которые полагались нанеявное преобразование в любом случае, по-видимому, потому что оно работало на целевых реализациях.Это было привлекательно, по стандартам некоторых людей в то время, в сочетании с правилами неявной типизации изначального Си.Можно позволить переменной или функции, предназначенной для возврата или сохранения указателя по умолчанию набирать int, вообще пропустив ее объявление, и до тех пор, пока оно интерпретируется как указатель везде, где оно в конечном итоге используется, все, как правило, работает как задумано.

Я склонен догадываться, что все, что продолжает работать, как предполагалось, тем самым поддерживая обратную совместимость, было разработчиком компилятора, который продолжал принимать неявные преобразования, так что это «позволяет компилировать [до] доисторический код»«.Однако я отмечаю, что в наши дни код с неявными преобразованиями такого рода гораздо реже работает, чем предполагалось, поскольку на многих машинах в наши дни есть 64-разрядные указатели, но только 32-разрядные int с.

0 голосов
/ 19 февраля 2019

Поведение присвоения арифметического типа указателю не очень хорошо сформировано в стандарте C.(См. Ответ, предоставленный R .. для соответствующих разделов.)

Ваш компилятор (или используемые вами настройки) решили рассматривать это как предупреждение.

Компиляторы имеют настройки по умолчаниюи часто поддерживают языковые расширения, и они могут быть довольно либеральными.

Обратите внимание, что за пределами языковой спецификации разработчики компилятора должны решить, что является ошибкой, или собираются ли они интерпретировать это как расширение языка и (надеюсь) выдать предупреждение о том, что кодне в официальной трассе.

Я согласен, что это не лучше.Моя рекомендация - исправить ошибку, потому что она почти наверняка есть, и приведение int к указателю является стандартным поддерживаемым способом явного выражения и получения того же результата (например, int * n).

Я думаю, что вы используете GCC, и он печально известен тем, что «услужливо» компилирует вещи, которые он может лучше обслуживать, отвергая и заставляя вас использовать стандартные конструкции.

Включить все предупреждения (-Wall в командной строке gcc) и убедитесь, что вы понимаете и решаете их все соответствующим образом.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...