Как разрешить: предупреждение "cast to pointer from integer of different size" в коде C?

Я удаляю gcc-предупреждения из устаревшего кода.

Можно ли подавить предупреждение "приведение к указателю из целого разного размера" с помощью typecasting:

example:

some_struct *ptr = func()  // func() returns an integer.

Может ли кто-нибудь мне посоветовать, как разрешить такие предупреждения gcc?

Ответ 1

Во-первых, если вы можете исправить func (разрешено изменять его источник), тогда исправьте его. Если его вычисления можно сделать с помощью указателей, то сделайте их с указателями и указателями возврата. Иногда есть веские причины для работы с адресами как целые числа (например, связанные с проблемами выравнивания в специальном коде). В этом случае измените func, чтобы использовать тип uintptr_t (определенный в stdint.h). Он предназначен для обработки указателей как целых чисел, когда это необходимо. (Существует также intptr_t, если по какой-то причине арифметика подписана лучше, но я обычно считаю unsigned uintptr_t менее неприятным.) Предпочтительно func должен преобразовать uintptr_t в указатель при его возврате, поэтому возвращаемый тип func будет указателем (что-то, возможно, some_struct или void).

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

В этом случае вы должны убедиться, что вычисление, выполняемое func, работает в новой архитектуре. Если он возвращает только 32-битное значение, будет ли оно всегда содержать правильное значение? То есть, ничто не будет потеряно отсутствующими высокими 32 битами? Нет адреса, который func должен вычислять когда-либо превышающий максимальное значение целочисленного типа, который он использует? Если func использует знаковые целочисленные типы, рассмотрите также знаковый бит.

Если вы гарантировали правильность значения, возвращаемого func, то вы можете использовать явные приведения, такие как: some_struct *ptr = (some_struct *) (intptr_t) func();.

Ответ 2

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

Я получаю предупреждение

assignment makes pointer from integer without a cast

Обратите внимание на часть "без литой". Таким образом, вы можете сделать gcc молчанием путем кастинга (без изменения поведения):

some_struct *ptr = (void*)func();

Затем вы получите свое предупреждение ( "приведение к указателю из целого разного размера" ), если возвращаемый тип func не подходит для адресов. Это может быть отключено путем дополнительного литья func() в подходящий целочисленный тип, например. intptr_t:

some_struct *ptr = (void*)(intptr_t)func();

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

Ответ 3

Здесь есть две возможности:

  • func - это фактический указатель на целое число; он позже используется как указатель.
  • func возвращает целое число, которое хранится в указателе; ptr позже преобразуется в целое число и используется как целое число.

В первом случае возвращаемое значение из func будет терять информацию и потенциально сбой или хуже, если int меньше размера указателя данных, который будет на большинстве 64-битные модели памяти (включая Windows и Linux). В этом случае вы должны изменить тип возврата func на intptr_t; см. Использование intptr_t вместо void *? и Почему/когда использовать `intptr_t` для литья типов в C?.

Во втором случае это менее проблема, но для решения проблем с контентом вы должны использовать intptr_t: some_struct *ptr = (some_struct *)(intptr_t)func(); и позже int value = (int)(intptr_t)ptr;. См. Макросы преобразования типа GLib для обсуждения проблемы.