С++ использует (void *) для приведения к int для сравнения?

Я (пытаюсь) написать некоторый (работающий) C++ в проекте ObjC :-) Библиотека C++ (Box2D) предоставляет мне класс b2Fixture, который имеет свойство «пользовательских данных», чтобы кодеры могли хранить все, что имеет к ним отношение.

В моем случае он просто должен хранить целое число. Из моей основной программы в ObjC нужно преобразовать целое число в void*:

headFixture->SetUserData( (void*) 10 );

В служебном методе на стороне программы C++ я хотел бы сравнить пользовательские данные с заданным целым числом (т.е. они являются константами, 10 = твердая земля, 11 = платформа и т. д.).

Первое сравнение использует (void*), которое отказывается компилироваться. На SO нашел другой подход, как показано во втором сравнении, в котором используется *( (intptr_t *) ... ). Тот компилируется, но отправляет EXC_BAD_ACCESS:

bool AbstractContactListener::contactContainsType(JRContact contact, int type){

    if (( type == ( (void *) contact.fixtureA->GetUserData() )) ||
        ( type == *( (intptr_t *) contact.fixtureB->GetUserData() ))
        ) {
        return true;
    }

    return false;
}

У меня заканчиваются идеи, чтобы подойти к этой проблеме. Помогите пожалуйста :-) Спасибо! Дж.

РЕДАКТИРОВАТЬ/РЕШЕНИЕ:

bool AbstractContactListener::contactContainsType(JRContact contact, int type){

    if (( type == (intptr_t) contact.fixtureA->GetUserData() ) ||
        ( type == (intptr_t) contact.fixtureB->GetUserData() )
        ) {
        return true;
    };

    return false;
}

Этот сработал для меня!


person Jem    schedule 05.02.2012    source источник
comment
Если вы разыменовываете недопустимый указатель в *contact.fixtureB->GetUserData(), то, конечно, произойдет сбой.   -  person Seth Carnegie    schedule 06.02.2012
comment
Я не понимаю, почему вам нужно использовать (void *). Вы храните что-то вроде числа, не так ли? Или SetUserData хранит указатель на число? Если бы вы могли написать немного о том, что делает SetUserData, это помогло бы.   -  person octopusgrabbus    schedule 06.02.2012
comment
@octopus: SetUserData — библиотечная функция, которая принимает void*. Это распространенный способ разрешить данные, предоставленные пользователем. Обычно вы сохраняете указатель на свои данные, а затем выполняете static_cast в T*, когда он передается вам в обратном вызове или что-то в этом роде. Однако, пока int не больше, чем void*, простое приведение его к void*, а затем обратно может избавить вас от необходимости выделять память для того, что является константой.   -  person R. Martinho Fernandes    schedule 06.02.2012
comment
@octopusgrabbus Мне пришлось, потому что SetUserData ( 10 ) не будет компилироваться из-за семантической проблемы: невозможно инициализировать параметр типа «void *» с помощью rvalue типа «int»   -  person Jem    schedule 06.02.2012
comment
Эй, спасибо всем за ваше время. См. вопрос редактирования для решения, которое сработало для меня.   -  person Jem    schedule 06.02.2012


Ответы (3)


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

#include <stdint.h>

if(type == (intptr_t)(contact.fixtureA->GetUserData())) {

Однако есть одно предостережение: насколько я знаю, приведение int к void* и обратно не гарантируется стандартом C для возврата одного и того же значения. Более безопасный вариант может состоять в том, чтобы просто использовать указатели так, как они предназначены для использования;

int *value = malloc(sizeof(int));
*value = 10;
headFixture->SetUserData( value );

и

if(type == *(int*)(contact.fixtureA->GetUserData())) {

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

person Joachim Isaksson    schedule 05.02.2012
comment
Хм, похоже, компилятору это не нравится :( Семантическая проблема: приведение от указателя к меньшему типу «int» теряет информацию. Я использую xcode, у него есть компилятор Apple LLVM 3. Спасибо :) - person Jem; 06.02.2012
comment
См. вопрос редактирования для решения, которое сработало для меня... Спасибо за ваше время! - person Jem; 06.02.2012
comment
Эй, интересная идея для malloc элемента размера int. Хороший! - person Jem; 06.02.2012

Я не совсем понимаю, что вы пытаетесь сделать, но вам, вероятно, следует привести данные обратно к тому типу, который вы хотите:

if (( type == reinterpret_cast<int>(contact.fixtureA->GetUserData() )) ||
    ( type == reinterpret_cast<int>(contact.fixtureB->GetUserData() ))
    ) {
person Pubby    schedule 05.02.2012
comment
На самом деле компилятор не позволит мне использовать == contact.fixtureA->GetUserData(), как будто он не может сравнить указатель с целым числом (используя компилятор Apple LLVM 3 - может быть, это причина?).. это причина; -) Хм, используя ваше предложение, я получаю преобразование из указателя в меньший тип 'int', теряет информацию, что препятствует компиляции :( - person Jem; 06.02.2012
comment
@jeM680000 Прочитайте комментарий Фернандеса. Пусть void* будет указателем на структуру, содержащую целое число. - person Pubby; 06.02.2012
comment
Эй, это не удалось. Но приведение к (intptr_t) без использования * сработало! Спасибо за ваше время :) - person Jem; 06.02.2012
comment
int, вероятно, является 32-битным значением, а ваш указатель 64-битным. (Насколько я понимаю, GetUserData() возвращает указатель, но вы просто используете его как число). Если это так, приведите void * к uint64_t, а int к uint64_t, тогда просто сравните. ПРИМЕЧАНИЕ. Это может привести к сбою в системе, требующей выравнивания, например, в некоторых процессорах ARM. - person EdH; 06.02.2012

Вы хотите использовать reinterpret_cast<int>. Если вы получаете сообщение об ошибке, значит, вы делаете не совсем то, что говорите. (Вероятно, вы пытаетесь разыменовать void * как int *.)

int stored_type = reinterpret_cast<int>(contact.fixtureA->GetUserData());
person moswald    schedule 05.02.2012
comment
См. вопрос редактирования для решения, которое сработало для меня... Спасибо за ваше время! - person Jem; 06.02.2012