ошибка: приведение от 'void *' к 'int' теряет точность - PullRequest
56 голосов
/ 29 октября 2009

У меня есть функция с прототипом void* myFcn(void* arg), которая используется в качестве начальной точки для pthread. Мне нужно преобразовать аргумент в int для дальнейшего использования:

int x = (int)arg;

Компилятор (GCC версии 4.2.4) возвращает ошибку:

file.cpp:233: error: cast from 'void*' to 'int' loses precision

Как правильно разыграть это?

Ответы [ 18 ]

61 голосов
/ 29 октября 2009

Вы можете привести его к типу intptr_t. Этот тип int гарантированно будет достаточно большим, чтобы содержать указатель. Используйте #include <cstdint>, чтобы определить его.

26 голосов
/ 26 августа 2011

Опять же, все ответы выше сильно упустили из виду. ОП хотел преобразовать значение указателя в значение int, вместо этого большинство ответов, так или иначе, пытались ошибочно преобразовать содержимое аргументов arg в значение int. И большинство из них даже не будет работать на gcc4.

Правильный ответ: если вы не против потери точности данных,

int x = *((int*)(&arg));

Это работает на GCC4.

Лучший способ, если можно, не делать такое приведение, вместо этого, если один и тот же адрес памяти должен быть разделен для указателя и int (например, для сохранения ОЗУ), используйте объединение и убедитесь, что в памяти адрес обрабатывается как int, только если вы знаете, что он был последний раз установлен как int.

11 голосов
/ 29 октября 2009

Нет правильного способа привести это значение к int в общем случае. Стандартная библиотека C99 предоставляет intptr_t и uintptr_t typedefs, которые должны использоваться всякий раз, когда возникает необходимость выполнить такое приведение. Если ваша стандартная библиотека (даже если это не C99) предоставляет эти типы - используйте их. Если нет, проверьте размер указателя на вашей платформе, самостоятельно определите эти typedef и используйте их.

8 голосов
/ 29 октября 2009

Вместо:

int x = (int)arg;

использование:

int x = (long)arg;

На большинстве платформ указатели и длинные значения имеют одинаковый размер, но на 64-битных платформах часто целочисленные значения и указатели часто не совпадают. Если вы преобразуете (void*) в (long), точность не теряется, а затем, присваивая (long) (int), он корректно усекает число для соответствия.

7 голосов
/ 29 октября 2009

Приведение указателя на void * и обратно является допустимым использованием reinterpret_cast <>. Так что вы можете сделать это:

pthread_create(&thread, NULL, myFcn, new int(5)); // implicit cast to void* from int*

Тогда в myFcn:

void* myFcn(void* arg)
{
    int*  data = reinterpret_cast<int*>(arg);
    int   x    = *data;
    delete data;

Примечание. Как указывает sbi, для создания потока потребуется изменить вызов OP.

Я пытаюсь подчеркнуть, что преобразование из int в указатель и обратно может привести к проблемам при переходе с платформы на платформу. НО преобразование указателя в void * и обратно хорошо поддерживается (везде).

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

4 голосов
/ 04 сентября 2013

вместо использования длинного приведения вы должны привести к size_t.

int val = (int) ((size_t) arg);

3 голосов
/ 29 октября 2009

Правильный способ - привести его к другому pointer type. Преобразование void* в int является непереносимым способом, который может работать или не работать! Если вам нужно сохранить возвращенный адрес, просто сохраните его как void*.

2 голосов
/ 03 апреля 2014

Я тоже сталкиваюсь с этой проблемой.

ids [i] = (int) arg; // здесь происходит ошибка => Я изменяю это ниже.

ids [i] = (uintptr_t) arg;

Тогда я могу продолжить компиляцию. Может быть, вы тоже можете попробовать это.

1 голос
/ 29 октября 2009

Если вы вызываете свою функцию создания потока, как это

pthread_create(&thread, NULL, myFcn, reinterpret_cast<void*>(5));

тогда void*, поступающий внутрь myFcn, имеет значение int, которое вы в него положили. Итак, вы знаете, что можете отбросить его обратно, как это

int myData = reinterpret_cast<int>(arg);

, хотя компилятор не знает, что вы когда-либо передаете myFcn в pthread_create вместе с целым числом.

Редактировать

Как указывал Мартин, это предполагает, что sizeof(void*)>=sizeof(int). Если у вашего кода есть шанс когда-либо перенести его на какую-либо платформу, где это не выполняется, это не сработает.

1 голос
/ 07 апреля 2011

Самый безопасный способ:

static_cast<int>(reinterpret_cast<long>(void * your_variable));

long гарантирует размер указателя в Linux на любой машине. Windows также имеет 32-битную длину только на 64-битной. Поэтому вам нужно изменить его на long long вместо long в Windows для 64 бит. Поэтому reinterpret_cast преобразует его в тип long, а затем static_cast безопасно преобразует long в int, если вы готовы, обрезайте данные.

...