C语言内存区域读取相关问题:变量正确性与数据读取方法
问题解答
一、变量声明与使用的问题修正
你的代码能运行但存在几个不规范和潜在崩溃的问题,逐个说明:
- 调用约定不匹配:原DLL函数是
__stdcall调用约定,但你自定义的A_ReadConfig指针没加这个修饰符。Windows下__stdcall函数的导出名会被修饰(比如变为_ReadConfig@8),如果DLL按此约定导出,GetProcAddress用"ReadConfig"可能找不到函数;即使侥幸找到,调用时栈处理也会出错,必须把自定义指针改成typedef unsigned short (__stdcall * A_ReadConfig)(void **, size_t *);。 - size_t初始化错误:
size_t sizeMemoryZone = NULL;是类型不匹配的写法,size_t是无符号整数类型,NULL是指针空值,正确初始化应为size_t sizeMemoryZone = 0;。 - 缺少错误检查:
LoadLibrary和GetProcAddress都可能失败(比如DLL不存在、函数名错误),返回NULL后直接调用会导致程序崩溃,必须添加检查逻辑。 - 未处理内存释放:DLL分配的
pointerMemoryZone不能直接用free释放,必须查看DLL文档,找到对应的内存释放函数(比如FreeConfig),否则会造成内存泄漏。
二、读取内存区域数据的方法
根据你提供的示意图(翻译后结构如下):
内存区域为带头部的配置列表:
- 头部:存储配置条目总数(
unsigned int类型)- 主体:紧随头部的是N个配置条目,每个条目包含:
- 条目类型(
unsigned short)- 条目数据长度(
size_t)- 条目数据(可变长度的字节流)
步骤1:定义匹配的结构体
先根据示意图结构定义对应的C结构体:
// 单个配置条目结构 typedef struct { unsigned short entryType; // 条目类型 size_t entryLength; // 条目数据的字节长度 char entryData[]; // 柔性数组,存储条目数据 } ConfigEntry; // 整个配置列表的头部结构 typedef struct { unsigned int entryCount; // 配置条目总数 ConfigEntry entries[]; // 柔性数组,存储所有条目 } ConfigList;
步骤2:类型转换与数据读取
将void*类型的pointerMemoryZone转换为ConfigList*,然后遍历读取每个条目:
// 先确认函数调用成功(需参考DLL文档,比如返回0表示成功) if (outputFunction == 0 && pointerMemoryZone != NULL) { ConfigList* configList = (ConfigList*)pointerMemoryZone; // 先检查内存大小是否至少能容纳头部 if (sizeMemoryZone >= sizeof(ConfigList)) { printf("配置条目总数:%u\n", configList->entryCount); // 遍历每个条目(用指针偏移避免柔性数组的对齐问题) char* currentPos = (char*)&configList->entries[0]; for (unsigned int i = 0; i < configList->entryCount; i++) { ConfigEntry* entry = (ConfigEntry*)currentPos; // 检查当前条目是否超出内存范围,防止越界访问 if (currentPos + sizeof(ConfigEntry) + entry->entryLength > (char*)pointerMemoryZone + sizeMemoryZone) { printf("第%u个条目数据越界,停止遍历\n", i+1); break; } // 输出条目信息 printf("\n第%u个条目:\n", i+1); printf(" 类型:%hu\n", entry->entryType); printf(" 长度:%zu\n", entry->entryLength); printf(" 内容:"); // 如果是字符串可以直接printf,二进制数据用fwrite输出 fwrite(entry->entryData, 1, entry->entryLength, stdout); printf("\n"); // 移动指针到下一个条目 currentPos += sizeof(ConfigEntry) + entry->entryLength; } } }
步骤3:释放内存
必须使用DLL提供的内存释放函数(比如FreeConfig)来释放pointerMemoryZone,不能用标准库的free,否则会跨堆释放导致崩溃:
// 定义释放函数的指针类型 typedef void (__stdcall * FreeConfig)(void* pData); // 获取释放函数指针 FreeConfig ptrFreeConfig = (FreeConfig)GetProcAddress(dllLoadOuput, "FreeConfig"); if (ptrFreeConfig != NULL && pointerMemoryZone != NULL) { ptrFreeConfig(pointerMemoryZone); }
修正后的完整代码
#include <stdio.h> #include <windows.h> // 严格匹配DLL的函数指针类型 typedef unsigned short (__stdcall * ReadConfig)(void** pDataOut, size_t* pSizeDataOut); typedef void (__stdcall * FreeConfig)(void* pData); // 对应示意图的配置结构 typedef struct { unsigned short entryType; size_t entryLength; char entryData[]; } ConfigEntry; typedef struct { unsigned int entryCount; ConfigEntry entries[]; } ConfigList; int main(int nbArg, char** listeArg) { unsigned short outputFunction; void* pointerMemoryZone = NULL; size_t sizeMemoryZone = 0; // 正确初始化 // 加载DLL并检查结果 HMODULE dllLoadOutput = LoadLibrary("dllFile.dll"); if (dllLoadOutput == NULL) { printf("DLL加载失败,错误码:%lu\n", GetLastError()); return 1; } // 获取ReadConfig函数指针并检查 ReadConfig ptrReadConfiguration = (ReadConfig)GetProcAddress(dllLoadOutput, "ReadConfig"); if (ptrReadConfiguration == NULL) { printf("获取ReadConfig函数失败,错误码:%lu\n", GetLastError()); FreeLibrary(dllLoadOutput); return 1; } // 调用DLL函数 outputFunction = ptrReadConfiguration(&pointerMemoryZone, &sizeMemoryZone); // 处理调用结果 if (outputFunction == 0 && pointerMemoryZone != NULL) { printf("\n读取到的配置内存大小:%zu\n\n", sizeMemoryZone); ConfigList* configList = (ConfigList*)pointerMemoryZone; if (sizeMemoryZone >= sizeof(ConfigList)) { printf("配置条目总数:%u\n", configList->entryCount); char* currentPos = (char*)&configList->entries[0]; for (unsigned int i = 0; i < configList->entryCount; i++) { ConfigEntry* entry = (ConfigEntry*)currentPos; if (currentPos + sizeof(ConfigEntry) + entry->entryLength > (char*)pointerMemoryZone + sizeMemoryZone) { printf("第%u个条目越界,终止遍历\n", i+1); break; } printf("\n第%u个条目:\n", i+1); printf(" 类型:%hu\n", entry->entryType); printf(" 长度:%zu\n", entry->entryLength); printf(" 内容:"); fwrite(entry->entryData, 1, entry->entryLength, stdout); printf("\n"); currentPos += sizeof(ConfigEntry) + entry->entryLength; } } // 释放DLL分配的内存 FreeConfig ptrFreeConfig = (FreeConfig)GetProcAddress(dllLoadOutput, "FreeConfig"); if (ptrFreeConfig != NULL) { ptrFreeConfig(pointerMemoryZone); } else { printf("\n未找到内存释放函数,可能存在内存泄漏\n"); } } else { printf("ReadConfig调用失败,返回码:%hu\n", outputFunction); } // 卸载DLL FreeLibrary(dllLoadOutput); return 0; }
内容的提问来源于stack exchange,提问作者Juan
相关产品推荐
相关产品推荐

