Ответ 1
Вы можете применить его к типу intptr_t
. Это тип int
гарантированно достаточно большой, чтобы содержать указатель. Используйте #include <cstdint>
, чтобы определить его.
У меня есть функция с прототипом 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
Каков правильный способ сделать это?
Вы можете применить его к типу intptr_t
. Это тип int
гарантированно достаточно большой, чтобы содержать указатель. Используйте #include <cstdint>
, чтобы определить его.
Опять же, все ответы выше пропустили плохо. OP хотел преобразовать значение указателя в значение int, вместо этого большинство ответов, так или иначе, пытались ошибочно преобразовать содержимое аргументов arg в значение int. И большинство из них даже не будут работать на gcc4.
Правильный ответ: если вы не против потери точности данных,
int x = *((int*)(&arg));
Это работает на GCC4.
Лучше всего, если можно, не делайте такого литья, вместо этого, если один и тот же адрес памяти должен быть общим для указателя и int (например, для сохранения ОЗУ), используйте union и убедитесь, что если mem адрес рассматривается как int, только если вы знаете, что он был последним установлен как int.
В общем случае нет подходящего способа сделать это для int
. Стандартная библиотека C99 предоставляет intptr_t
и uintptr_t
typedefs, которые должны использоваться всякий раз, когда возникает необходимость выполнить такой отбор. Если ваша стандартная библиотека (даже если это не C99), оказывается, предоставляет эти типы - используйте их. Если нет, проверьте размер указателя на своей платформе, самостоятельно определите эти typedefs и используйте их.
Вместо:
int x = (int)arg;
использование:
int x = (long)arg;
На большинстве платформ указатели и longs имеют одинаковый размер, но ints и указатели часто не равны по размеру на 64-битных платформах. Если вы конвертируете (void*
) в (long
), точность не теряется, то, назначив (long
) на (int
), он должным образом усекает число, которое должно соответствовать.
Приведение указателя в 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 * и обратно снова хорошо поддерживается (везде).
Таким образом, в результате может быть меньше склонности к ошибкам генерировать указатель динамически и использовать его. Помните о необходимости удалить указатель после использования, чтобы мы не просочились.
вместо того, чтобы использовать длинный бросок, вы должны наложить на size_t.
int val = (int) ((size_t) arg);
Правильный способ - передать его другому pointer type
. Преобразование a void*
в int
является не переносным способом, который может работать или не может быть! Если вам нужно сохранить возвращенный адрес, просто сохраните его как void*
.
Я тоже встречаюсь с этой проблемой.
ids [i] = (int) arg;//здесь возникает ошибка = > Я изменяю это ниже.
ids [i] = (uintptr_t) arg;
Затем я могу продолжить компиляцию. Возможно, вы тоже можете попробовать.
Если вы вызываете функцию создания потока, подобную этой
pthread_create(&thread, NULL, myFcn, reinterpret_cast<void*>(5));
то void*
, входящий внутрь myFcn
, имеет значение int
, которое вы вложили в него. Итак, вы знаете, что можете отбросить это назад.
int myData = reinterpret_cast<int>(arg);
даже несмотря на то, что компилятор не знает, что вы только передаете myFcn
в pthread_create
в сочетании с целым числом.
Edit:
Как указывал Мартин, это предполагает, что sizeof(void*)>=sizeof(int)
. Если ваш код имеет возможность портироваться на какую-либо платформу, где это не выполняется, это не сработает.
Самый безопасный способ:
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
, если вы готовы сделать truncte данных.
Я бы создал структуру и передал ее как void * в pthread_create
struct threadArg {
int intData;
long longData;
etc...
};
threadArg thrArg;
thrArg.intData = 4;
...
pthread_create(&thread, NULL, myFcn, (void*)(threadArg*)&thrArg);
void* myFcn(void* arg)
{
threadArg* pThrArg = (threadArg*)arg;
int computeSomething = pThrArg->intData;
...
}
Имейте в виду, что thrArg должен существовать до тех пор, пока myFcn() не использует его.
Нет никакого "правильного" способа хранения 64-разрядного указателя в 32-разрядном целое. Проблема заключается не в кастинге, а в том, что целевой тип теряет половину указателя. 32 оставшихся бита, хранящихся внутри int
, недостаточны для восстановления указателя на функцию потока. Большинство ответов просто пытаются извлечь 32 бесполезных бита из аргумента.
Как Ferruccio, int должен быть заменен на intptr_t
, чтобы сделать программу значимой.
Не передавайте свой int как void*
, передайте int*
на ваш int
, поэтому вы можете наложить void*
на int*
и скопировать указатель разыменования на ваш int
.
int x = *static_cast<int*>(arg);
Что вы можете пожелать, это
int x = reinterpret_cast<int>(arg);
Это позволяет вам переосмыслить void *
как int
.
//new_fd is a int
pthread_create(&threads[threads_in_use] , NULL, accept_request, (void*)((long)new_fd));
//inside the method I then have
int client;
client = (long)new_fd;
Надеюсь, что это поможет
В моем случае я использовал 32-битное значение, которое нужно было передать функции OpenGL в виде void *, представляющего смещение в буфер.
Вы не можете просто перевести 32-битную переменную в указатель, потому что этот указатель на 64-битной машине в два раза длиннее. Половина вашего указателя будет мусором. Вам нужно передать фактический указатель.
Это даст вам указатель на 32-битное смещение:
int32 nOffset = 762; // random offset
char * pOffset = NULL; // pointer to hold offset
pOffset += nOffset; // this will now hold the value of 762 correctly
glVertexAttribPointer(binding, nStep, glType, glTrueFalse, VertSize(), pOffset);
Указатель функции несовместим с void * (и любым другим указателем нефункции)
Ну, это происходит потому, что вы конвертируете 64-битный указатель в 32-битное целое число, чтобы потерять информацию.
Вы можете использовать целое число из 64 бит вместо howerver. Обычно я использую функцию с правильным прототипом, и я использую тип функции: например.
void thread_func(int arg){
...
}
и я создаю поток следующим образом:
pthread_create(&tid, NULL, (void*(*)(void*))thread_func, (void*)arg);