【问题标题】:Pointer to Pointer to Void Function Parameter指向 void 函数参数的指针的指针
【发布时间】:2015-02-05 15:34:34
【问题描述】:

我有一个我正在修改的驱动程序,它是由其他人用 C 编写的。由于我需要添加一些 C++ 函数调用,我现在使用 C++ 编译器而不是 C 编译器(在 Visual Studio 2012 中)构建驱动程序。当我改用 C++ 时,我收到了很多构建错误,除了少数之外,我都能修复所有这些错误。少数错误都与对同一函数的调用有关。我在网上广泛搜索,试图找到解决这个问题的方法,但没有成功。所以下面是这个问题的组成部分,我希望能让有人帮助我解决这个问题。

首先,这里是被调用的函数。您可能想知道为什么最初的 S/W 开发人员可以在标准 C 库中使用 free() 函数时创建自己的自定义空闲内存函数。我不知道为什么会这样,但因为它工作得很好,我犹豫要改变它。

void freeMemory(void **pBuffer)
{
    BOOL result;
    ASSERT(pBuffer != NULL);

    // see if buffer is already been freed
    if (*pBuffer == NULL)
    {   
        return;
    }

    result = VirtualFree(
        *pBuffer,                   // LPVOID lpAddress,   // address of memory
        0,                          // SIZE_T dwSize,      // size of memory
        MEM_RELEASE                 // DWORD dwFreeType    // operation type
        );
    // see of we were able to successfully free the memory  
    if (result == FALSE)
    {   
        ASSERT(FALSE);
        return;
    }

    // Mark the buffer pointer as now being free
    *pBuffer = NULL;
}  

所以这个难题的下一个部分是#define,如下所示:

#define FREE(pBuffer) freeMemory(&(pBuffer))

最后,下面是对这个 FREE 函数的众多调用之一:

FREE(Buffer);

在本例中,“Buffer”是指向无符号字符的指针。

unsigned char *Buffer;

出于参考目的,对于这个特定示例,我收到的错误是“无法将参数 1 从 'unsigned char *' 转换为 'void **'”

我已经很久没有使用 C 或 C++ 做过很多事情了,而指针从来都不是我的强项。基于该错误,我的假设是此错误与未在函数调用中提供强制转换有关,但考虑到如何从标准 C 库中使用 free() 函数,似乎没有必要这样做。任何关于如何调用 FREE 函数以消除这些错误的帮助,我们将不胜感激。

【问题讨论】:

  • 内存最初是由 VirtualAlloc 提交的吗?
  • 那个错误信息应该是“[...] from unsigned char ** to void **[...]” 并且这个转换在 C 中也不能工作.
  • 简单地使用#define FREE(pBuffer) freeMemory(&((void*)(pBuffer)))怎么样?
  • @alk - 我尝试了你的建议,现在得到“错误 C2102:'&' 需要 l-value”

标签: c++ c pointers


【解决方案1】:

我在运行您的代码变体时遇到的问题是 VirualFree 和 VirtualAlloc 的使用不一致,即在您提供的代码示例中,我看不到 VirtualAlloc() 用法的指示,应该与 VirtualFree() 一起使用.

另外,当我尝试使用VirtualAlloc() 将内存分配给特定地址时,它总是失败,所以我让系统指定地址。下面是演示分配和释放页内存的代码 sn-p。

编辑 现在解决您的宏问题,它使用 Jonaton 的宏定义建议(带有两个额外的 ;)。

Adapted from here:(这个构建和运行没有错误,展示了 VirtualAlloc()VirtualFree() 结合使用)

#include <windows.h>
#include <stdio.h>
#include <stdlib.h>             

#define PAGES 100            

LPTSTR lpNxtPage;               
DWORD dwPages = 0;              
DWORD dwPageSize;

void freeMemory(void **pBuffer);

#define FREE(pBuffer) \
{ \
    void *tmp; \
    tmp = pBuffer; \
    freeMemory(&tmp); \
    pBuffer = tmp; \
}

void main(void)
{
    LPVOID lpvBase;               
    LPTSTR lpPtr;                 
    BOOL bSuccess;                
    DWORD i;                      
    SYSTEM_INFO sSysInfo;         

    GetSystemInfo(&sSysInfo);     


    dwPageSize = sSysInfo.dwPageSize;


    lpvBase = VirtualAlloc(
                     NULL,                 
                     PAGES*dwPageSize, 
                     MEM_RESERVE,          
                     PAGE_NOACCESS);       
    if (lpvBase == NULL )//do nothing

    lpPtr = lpNxtPage = (LPTSTR) lpvBase;


   // bSuccess = VirtualFree(
   //                    lpvBase,       
   //                    0,             
   //                    MEM_RELEASE); 
    FREE(lpvBase)  //replace in-line VirtualFree with macro

    ;
}


void freeMemory(void **pBuffer)
{
    BOOL result;
    assert(pBuffer != NULL);

    // see if buffer is already been freed
    if (*pBuffer == NULL)
    {   
        return;
    }

    result = VirtualFree(
        *pBuffer,                   // LPVOID lpAddress,   // address of memory
        0,                          // SIZE_T dwSize,      // size of memory
        MEM_RELEASE                 // DWORD dwFreeType    // operation type
        );
    // see of we were able to successfully free the memory  
    if (result == FALSE)
    {   
        assert(FALSE);
        return;
    }

    // Mark the buffer pointer as now being free
    *pBuffer = NULL;
} 

【讨论】:

  • ryyker - 如上面我的 cmets 所述,如果我用你的新宏替换旧宏,我现在得到“错误 C2440:'=':无法从 'void *' 转换为 'unsigned char * ’”。因为只有几次对 FREE() 的调用,所以我最终消除了宏,只是将代码放入行中,从而消除了构建错误。只要我知道它正确地释放了内存,我就感觉还可以。相对于您对 VirualAlloc() 用法的评论,该程序还有另一个类似于 freeMemory 的函数,它包装了 VirualAlloc() 并有效地匹配您的代码。
【解决方案2】:

freeMemory 用于创建一个安全的空闲空间,因为您可以为同一个指针调用两次而不会造成任何伤害。我不喜欢这样,它只会隐藏你的错误,但很常见。

正如 Quentin 所指出的那样,here 解释了此错误的原因。

您的代码的替代方案是:

#define FREE(pBuffer) \
{ \
    void *tmp; \
    tmp = pBuffer; \
    freeMemory(&tmp); \
    pBuffer = tmp; \
}

【讨论】:

  • 您的回答中缺少几个;
  • 我添加了必要的 ';'到乔纳坦答案中的代码行,但我现在收到该代码的构建错误,上面写着“错误 C2447:'{':缺少函数头(旧式正式列表?)”
  • @Pungo120 - 它可能是对需要函数原型的引用吗?顺便说一句,我在你的代码中实现了 Jonatan 的代码,运行了它,但 VirtualFree(...) 无法释放内存。除此之外,我没有收到任何错误消息。这可能是因为第二个参数是 0。我现在正在查看 documentation
  • @ryyker - freeMemory() 的函数原型存在。它与#define FREE(pBuffer) 存在于同一个头文件中...我将#define 移到函数原型下方以防万一这是一个问题但没有区别。
  • 好的。我消除了“错误C2447:'{':缺少函数头(旧式正式列表?)”,但现在我得到了一个稍微不同的错误。为澄清起见,“完整”原始错误消息是“错误 C2664:'freeMemory':无法将参数 1 从 'unsigned char *' 转换为 'void **'”。用 Jonatan 建议的代码替换原来的#define,我现在得到“error C2440: '=' : cannot convert from 'void *' to 'unsigned char *'”
猜你喜欢
  • 2018-04-19
  • 1970-01-01
  • 1970-01-01
  • 2020-06-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-07-19
  • 1970-01-01
相关资源
最近更新 更多