【问题标题】:How do I cast int** to void**?如何将 int** 转换为 void**?
【发布时间】:2019-11-19 11:54:48
【问题描述】:

使用以下sn-p:

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

我在 Visual Studio 中收到以下错误:

int** 类型的值不能用于初始化void ** 类型的实体。

这很好用:

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

但是这段代码 sn-p 是针对某人库中的一个更大的问题。

将变量强制转换为 void** 有什么问题?

完整示例

使用caen digitizer library他们尝试从外围设备收集数据的方式有这个原型:

/******************************************************************************
* 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)

希望这能提供一些背景信息。

【问题讨论】:

  • void ** v = (void**)&c;
  • @MichaelChourdakis Success,你介意写一个答案来解释为什么这个演员有效吗?
  • @MichaelChourdakis 这真是糟糕的建议。您所做的只是抑制编译器警告。
  • 为什么这个问题甚至被标记为 c++。一切都在尖叫 c.
  • @TarickWelling 抱歉,我对细微差别的区别并不强烈。我会更改标签。

标签: c++ casting void void-pointers


【解决方案1】:

将变量强制转换为 void** 我做错了什么?

没有将int** 转换为void** 的有意义的方法,所以您尝试做的事情是错误的。

你可以做的是

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

但如果没有完整的例子,无法说是否适用于您的问题。

【讨论】:

  • 添加了您感兴趣的问题的上下文。
【解决方案2】:

这就是语言的工作原理。

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


在 cmets 中建议您使用 void ** v = (void**)&amp;c;

虽然您可以可能让它在实践中发挥作用,但严格来说,任何对*v 的访问都会违反strict aliasing 并导致未定义的行为。我不会使用那个解决方案。

【讨论】:

    【解决方案3】:

    void** 表示指向void* 对象的指针。但是该代码中没有 void* 对象指向! void** 并不意味着“指向任何类型指针的指针”,因此请避免使用它。如果你有一个指针,它可能是 int*,可能是 double*,等等,void* 是比 void** 更好的类型。更好的是模板或std::variantstd::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);
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-09-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-12-03
      • 2013-11-18
      • 1970-01-01
      相关资源
      最近更新 更多