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

Как я должен обрабатывать "cast from" void * to "int loses precision" при компиляции 32-битного кода на 64-битной машине?

У меня есть пакет, который компилируется и отлично работает на 32-битной машине. Теперь я пытаюсь собрать его на 64-битной машине и найти следующую ошибку -

 error: cast from ‘void*’ to ‘int’ loses precision

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

4b9b3361

Ответ 1

Проблема заключается в том, что в 32 битах int (который является 32-битным целым числом) будет содержать значение указателя.

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

Ответ 2

Ваш код не работает. Он не станет менее разрушенным, игнорируя предупреждения, предоставленные компилятором.

Как вы думаете, что произойдет, когда вы попытаетесь сохранить указатель шириной 64 бит в 32-битное целое число? Половина ваших данных будет выброшена. Я не могу представить много случаев, когда это правильная вещь, или где она не вызовет ошибок.

Исправьте свой код. Или оставайтесь на 32-битной платформе, на которой работает данный код.

Если ваш компилятор определяет intptr_t или uintptr_t, используйте их, поскольку они являются целыми типами, которые гарантируют, что они будут достаточно большими для хранения указателя.

Если эти типы недоступны, size_t или ptrdiff_t также достаточно велики, чтобы удерживать указатель на большинстве (не всех) платформ. Или используйте long (обычно это 64-разрядные на 64-разрядных платформах в компиляторе GCC) или long long (типы C99, которые большинство, но не все компиляторы, поддерживают на С++) или какой-либо другой определенный в реализации интегральный тип шириной не менее 64 бит на 64-битной платформе.

Ответ 3

Мое предположение - ситуация с ОП - это пустота * используется как общее хранилище для int, где void * больше, чем int. Итак, например:

int i = 123;
void *v = (void*)i;    // 64bit void* being (ab)used to store 32bit value
[..]
int i2 = (int)v;       // we want our 32bits of the 64bit void* back

Компилятор не любит эту последнюю строку.

Я не буду взвешивать, правильно ли или неправильно злоупотреблять пустотой * таким образом. Если вы действительно хотите обмануть компилятор, следующий метод работает, даже с -Wall:

int i2 = *((int*)&v);

Здесь он принимает адрес v, преобразует адрес в указатель нужного типа данных, затем следует указатель.

Ответ 4

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

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

Ответ 5

Листинг указателя на int ужасно с точки зрения переносимости. Размер int определяется сочетанием компилятора и архитектуры. Вот почему был создан заголовок stdint.h, чтобы вы могли явно указать размер используемого вами типа на разных платформах со многими различными размерами слов.

Вам лучше сбрасывать на uintptr_t или intptr_t (из stdint.h и выбирать тот, который лучше всего соответствует требуемой подписке).

Ответ 6

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

Ответ 7

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

Если вы подавляете ошибки, это может даже работать некоторое время. Хотя указатель указывает на адрес в первых 4 ГБ, верхние 32 бита будут равны 0, и вы не потеряете никаких данных. Но как только вы получите адреs > 4 ГБ, ваш код начнет "таинственно" не работать.

Что вам нужно сделать, это изменить любой int, который может содержать указатель на intptr_t.

Ответ 8

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

Ответ 9

Подавление предупреждений - плохая идея, но может быть флаг компилятора для использования 64-битных ints, в зависимости от вашего компилятора и архитектуры, и это безопасный способ исправить проблему (предполагая, конечно, что код didn 't также предположить, что ints 32-бит). Для gcc флаг -m64.

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

Ответ 10

Как определено текущим стандартом С++, нет целочисленного типа, который гарантированно удерживает указатель. На некоторых платформах будет intptr_t, но это не стандартная функция С++. По сути, обработка битов указателя, как если бы они были целыми числами, не является переносимой задачей (хотя ее можно заставить работать на многих платформах).

Если причина приведения заключается в том, чтобы сделать указатель непрозрачным, то void * уже достигает этого, поэтому код может использовать void * вместо int. Typedef может сделать это немного лучше в коде

typedef void * handle_t;

Если причина для актера состоит в том, чтобы сделать арифметику указателя с гранулярностью байт, тогда лучший способ - это, вероятно, применить к (char const *) и выполнить математику с этим.

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

Ответ 11

У меня возникла аналогичная проблема. Я решил это следующим образом:

 #ifdef 64BIT
 typedef uint64_t tulong;
 #else
 typedef uint32_t tulong;
 #endif

 void * ptr = NULL; //Whatever you want to keep it.
 int  i;
 i = (int)(tulong)ptr;

Я думаю, проблема заключается в приведении указателя в более короткий тип данных. Но для более крупного типа int он отлично работает.

Я преобразовал эту проблему из typecasting указателя на long в typecasting 64-битное целое число до 32-битного целого числа, и он работал нормально. Я все еще в поиске опции компилятора в GCC/Clang.

Ответ 12

Иногда бывает разумно разбить 64-битный элемент на 2 32-битных элемента. Вот как вы это сделаете:

Заголовочный файл:

//You only need this if you haven't got a definition of UInt32 from somewhere else
typedef unsigned int UInt32;

//x, when cast, points to the lower 32 bits
#define LO_32(x) (*( (UInt32 *) &x))

//address like an array to get to the higher bits (which are in position 1)
#define HI_32(x) (*( ( (UInt32 *) &x) + 1)) 

Исходный файл:

//Wherever your pointer points to
void *ptr = PTR_LOCATION 

//32-bit UInt containing the upper bits
UInt32 upper_half = HI_32(ptr); 

//32-bit UInt containing the lower bits
UInt32 lower_half = LO_32(ptr);