NSInvocation не передает указатель на массив c ++ - PullRequest
2 голосов
/ 01 октября 2010

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

Я вызываю метод объекта Objective-C из класса C ++ (который заблокирован). Я использую NSInvocation, чтобы мне не пришлось писать сотни методов только для доступа к данным в этом другом объекте.

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

float s2[3];
id args2s[] = {(id)&_start.x(),(id)&_start.y(),(id)&s2};
_view->_callPixMethod(@selector(convertPixX:pixY:toDICOMCoords:),3,args2s);

Это метод View, вызываемый

invokeUnion View::_callPixMethod(SEL method, int nArgs, id args[])
{
    DataModule* data;
    DataVisitor getdata(&data);
    getConfig()->accept(getdata);
    invokeUnion retVal;
    retVal.OBJC_ID = data->callPixMethod(_index, _datasetKey, method, nArgs, args);
    return retVal;
}

Invoke Union - это объединение, поэтому я могу получить значение с плавающей запятой, возвращаемое NSInvocation.

union invokeUnion {
id OBJC_ID;
int intValue;
float floatValue;
bool boolValue;
};

Это метод в объекте данных (pthread заблокирован с помощью lock () и unlock ());

id DataModule::callPixMethod(int index, std::string predicate, SEL method, int nArgs, id args[] )
{
    // May Block
    DCMPix *pix =[[getSeriesData(predicate) pix] objectAtIndex:index];

    lock();

    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

    NSMethodSignature *signature;
    NSInvocation *invocation;

    signature = [DCMPix instanceMethodSignatureForSelector:method];
    invocation = [NSInvocation invocationWithMethodSignature:signature];

    [invocation setSelector:method];
    [invocation setTarget:pix];

    if (nArgs > 0) for (int n = 0; n < nArgs; n++) {
        SFLog(@"invocation: i=%d, *ptr=0x%x, valf=%f, vald=%d",n,args[n],*args[n],*args[n]);
        [invocation setArgument:args[n] atIndex:2+n];
    }

    id retVal;

    [invocation invoke];
    [invocation getReturnValue:&retVal];

    [pool release];

    unlock();

    return retVal;
}

Метод в объекте DCMPix (который я не могу изменить, это часть библиотеки) следующий:

-(void) convertPixX: (float) x pixY: (float) y toDICOMCoords: (float*) d pixelCenter: (BOOL) pixelCenter
{
    if( pixelCenter)
    {
        x -= 0.5;
        y -= 0.5;
    }

    d[0] = originX + y*orientation[3]*pixelSpacingY + x*orientation[0]*pixelSpacingX;
    d[1] = originY + y*orientation[4]*pixelSpacingY + x*orientation[1]*pixelSpacingX;
    d[2] = originZ + y*orientation[5]*pixelSpacingY + x*orientation[2]*pixelSpacingX;
}

-(void) convertPixX: (float) x pixY: (float) y toDICOMCoords: (float*) d
{
    [self convertPixX: x pixY: y toDICOMCoords: d pixelCenter: YES];
}

Сбой при попытке доступа к d[0]. BAD_EXC_ACCESS что, как я знаю, означает, что он обращается к освобожденной памяти или к памяти, находящейся за пределами ее области действия.

Я заблудился, отслеживая мои указатели на указатели. два значения с плавающей точкой встречаются нормально (как и другая информация в других методах), но это единственное, которое запрашивает float* в качестве параметра. Из того, что я понимаю, метод convertPixX: был преобразован из программы на C, написанной для Mac OS 9 ... вот почему он запрашивает массив c в качестве значения out ... Я думаю.

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

Я пытался отправить значение следующим образом:

float *s2 = new float[3];
void* ps2 = &s2;
id args2s[] = {(id)&_start.x(),(id)&_start.y(),(id)&ps2};
_view->_callPixMethod(@selector(convertPixX:pixY:toDICOMCoords:),3,args2s);

Но это дает SIGKILL - плюс я уверен, что это фальшивка и неправда. ... но я пытался.

в любом случае ... указатели! межъязыковой! Argh!

Спасибо

1 Ответ

0 голосов
/ 01 октября 2010

Массив не является указателем.Попробуйте добавить следующую строку

NSLog(@"%p, %p", s2, &s2);

чуть выше.

id args2s[] = {(id)&_start.x(),(id)&_start.y(),(id)&s2};

s2 и & s2 - это адреса первого числа с плавающей точкой в ​​вашем массиве, поэтому, когда вы делаете:

[invocation setArgument:args[n] atIndex:2+n];

для n = 2, вы копируете не указатель на первый с плавающей точкой, а первый с плавающей точкой, возможно, первые два с плавающей точкой, если идентификатор имеет ширину 64 бита.

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

Чтобы решить эту проблему, это может сработать (не проверено).

float s2[3];
float* s2Pointer = s2;
id args2s[] = {(id)&_start.x(),(id)&_start.y(),(id)&s2Pointer};
_view->_callPixMethod(@selector(convertPixX:pixY:toDICOMCoords:),3,args2s);

s2Pointer - реальный указатель, который даст вам двойное косвенное обращение.

...