Как я могу разыграть int ** в void **? - PullRequest
2 голосов
/ 10 июля 2019

Со следующим фрагментом:

int n = 11;
int* c = &n;
void** v = &c;

Я получаю следующую ошибку в Visual Studio:

значение типа int** нельзя использовать для инициализации объектавведите void **.

Это прекрасно работает:

int n = 11;
int* c = &n;
void* v = c;

Но этот фрагмент кода предназначен для более серьезной проблемы в чьей-то библиотеке.

Что я делаюнеправильно с приведением переменной к void**?

Полный пример

Использование библиотеки цифрового преобразователя caen способ, которым они пытаются собрать данные с периферийного устройства, имеет этот прототип:

/******************************************************************************
* X742_DecodeEvent(char *evtPtr, void **Evt)
* Decodes a specified event stored in the acquisition buffer writing data in Evt memory
* Once used the Evt memory MUST be deallocated by the caller!
*
* [IN]  EventPtr : pointer to the requested event in the acquisition buffer (MUST BE NULL)
* [OUT] Evt      : event structure with the requested event data
*                : return  0 = Success; 
******************************************************************************/
int32_t X742_DecodeEvent(char *evtPtr, void **Evt);

И это реализация:

int32_t X742_DecodeEvent(char *evtPtr, void **Evt) {
    CAEN_DGTZ_X742_EVENT_t *Event;
    uint32_t *buffer;
    char chanMask;
    uint32_t j,g,size;
    uint32_t *pbuffer;
    uint32_t eventSize;
    int evtSize,h;

    evtSize = *(long *)evtPtr & 0x0FFFFFFF;
    chanMask = *(long *)(evtPtr+4) & 0x0000000F;
    evtPtr += EVENT_HEADER_SIZE;
    buffer = (uint32_t *) evtPtr;
    pbuffer = (uint32_t *) evtPtr;
    eventSize = (evtSize * 4) - EVENT_HEADER_SIZE;
    if (eventSize == 0) return -1;
    Event = (CAEN_DGTZ_X742_EVENT_t *) malloc(sizeof(CAEN_DGTZ_X742_EVENT_t));
    if (Event == NULL) return -1;
    memset( Event, 0, sizeof(CAEN_DGTZ_X742_EVENT_t));
    for (g=0; g<X742_MAX_GROUPS; g++) {
        if ((chanMask >> g) & 0x1) {
        for (j=0; j<MAX_X742_CHANNEL_SIZE; j++) {
            Event->DataGroup[g].DataChannel[j]= malloc(X742_FIXED_SIZE * sizeof (float));
            if (Event->DataGroup[g].DataChannel[j] == NULL) {
                for (h=j-1;h>-1;h++) free(Event->DataGroup[g].DataChannel[h]);
                return -1;
            }
        }
        size=V1742UnpackEventGroup(g,pbuffer,&(Event->DataGroup[g]));
        pbuffer+=size;
        Event->GrPresent[g] = 1;    
        } 
        else {
            Event->GrPresent[g] = 0;
            for (j=0; j<MAX_X742_CHANNEL_SIZE; j++) {
                Event->DataGroup[g].DataChannel[j] = NULL;
            }
        }
    }
    *Evt = Event;
    return 0;
}

Я использую это следующим образом:

CAEN_DGTZ_X742_EVENT_t* Evt = NULL; // Creating my event pointer
//Doing some config of the device
X742_DecodeEvent(evtptr, &Evt); //Decode the event data for me to read (Throws error)

Надеюсь, что это дает некоторый контекст.

Ответы [ 3 ]

4 голосов
/ 10 июля 2019

Что я делаю не так с приведением переменной к void **?

Нет никакого значимого способа конвертировать int** в void**, поэтому то, что вы пытаетесь сделать, неверно.

Что вы можете сделать, это

int n = 11;
void* c = &n;
void** v = &c;

Но без полного примера невозможно сказать, применимо ли это к вашей проблеме.

3 голосов
/ 10 июля 2019

void** означает указатель на void* объект.Но в этом коде нет объекта void*, на который можно было бы указать!void** НЕ означает «указатель на любой вид указателя», поэтому, пожалуйста, избегайте его использования как такового.Если у вас есть указатель на что-то, что может быть int*, может быть double* или т. Д., void* лучше, чем void**.Еще лучше будет шаблон или std::variant или std::any.

Но если вам нужно использовать библиотеку, которая использует void** для обозначения "указателя на указатель на тип, неизвестный во время компиляции"или что-то в этом роде, вам может понадобиться создать указатель void* для работы, или вам может понадобиться добавить в приведения, чтобы обойти тот факт, что компилятору не нравится это преобразование (по уважительной причине).Проблема в том, что есть как минимум два разумных способа сделать это!(В конечном итоге они будут делать одно и то же на многих распространенных компьютерных архитектурах, но это не гарантируется.)

// LibraryFunc1 takes a void** argument that somehow means an int* pointer.
// But which call is correct?
int* data_in = generate_data();
LibraryFunc1(reinterpret_cast<void**>(&data_in)); // ?
void* p1 = data_in;
LibraryFunc1(&p1); // ?

// LibraryFunc2 returns a void** argument that somehow means an int* pointer.
void** p2 = LibraryFunc2();
int* data_out_1 = static_cast<int*>(*p2); // ?
int* data_out_2 = *reinterpret_cast<int**>(p2); // ?

Основываясь на показанном определении функции, безопасное использование, к сожалению:

void* tmpEvt;
X742_DecodeEvent(evtptr, &tmpEvt);
auto* Evt = static_cast<CAEN_DGTZ_X742_EVENT_t*>(tmpEvt);

, поскольку библиотечная функция предполагает в *Evt = Event;, что *Evt на самом деле является void* объектом, который она может изменить.Обычно вместо этого может работать более простая вещь:

CAEN_DGTZ_X742_EVENT_t* Evt = NULL;
X742_DecodeEvent(evtptr, reinterpret_cast<void**>(&Evt));

, но это стандарт C ++, и это может привести к неправильным действиям на некоторых архитектурах.

Вы можете сделатьисправить это проще, обернув его в функцию:

inline CAEN_DGTZ_X742_EVENT_t* Get_X742_DecodeEvent(char* evtPtr)
{
    void* tmpEvt;
    X742_DecodeEvent(evtPtr, &tmpEvt);
    return static_cast<CAEN_DGTZ_X742_EVENT_t*>(tmpEvt);
}
1 голос
/ 10 июля 2019

Это просто, как работает язык.

void * указатели получают специальную обработку: указатель на произвольный тип может быть преобразован в указатель в void (если это не удаляет cv-qualifiers из указателя) .

void ** не получает никакого специального лечения. Это просто обычный тип указателя, например int **.


int32_t X742_DecodeEvent(char *evtPtr, void **Evt)

Поскольку вы хотите передать CAEN_DGTZ_X742_EVENT_t ** в вашу функцию, вы должны соответственно изменить тип параметра: CAEN_DGTZ_X742_EVENT_t **Evt.


В комментариях вам предложили использовать void ** v = (void**)&c;.

Хотя вы могли бы , вероятно, заставить это работать на практике, строго говоря, любой доступ к *v нарушил бы строгий псевдоним и вызвал бы неопределенное поведение. Я бы не использовал это решение.

...