C++ DLL char* 返回问题
Posted
技术标签:
【中文标题】C++ DLL char* 返回问题【英文标题】:C++ DLL char* return issue 【发布时间】:2018-01-05 07:24:03 【问题描述】:我有一个 C++ DLL 函数,它接收一个 char * 并返回一个 char*。
DLL函数的定义是:
char * scanImage( char * fileDir)
string dir(fileDir);
string cvStr = cvScan(dir);
char * scanReturn = &cvStr[0];
cout << scanReturn << endl;
return (scanReturn);
客户端功能是:
int main()
char * ret;
ret = scanImage("files/stu2/1.bmp");
cout << ret << endl;
return 0;
现在DLL 函数 的cout 打印出正确的输出,这意味着参数正在传递而没有任何问题。但是 client function 的 cout 会打印出类似这样的内容-
我出于测试目的打印了 ret[i]。这总是在范围内返回 -35。还有strlen(ret) > strlen(scanReturn)。
我使用 std::string 而不是 char* 作为参数和返回值。那工作得很好。但我不能使用字符串(我想稍后将此 DLL 与 VB.NET 应用程序一起使用,字符串不适合那个,或者会?)。
现在如何解决这个问题?我正在使用 Visual C++ 在 Visual Studio 2017 IDE 中编译 DLL 和客户端程序。
更新:
char * scanImage( char * fileDir)
string dir(fileDir);
string cvStr = cvScan(dir);
char * scanReturn;
scanReturn = (char*)malloc(sizeof(char)* cvStr.size());
scanReturn = &cvStr[0];
cout << "DLL Output: " << endl << scanReturn << endl;
return (scanReturn);
为 scanReturn 动态分配内存。但我仍然遇到同样的问题。
【问题讨论】:
这是关于返回指向局部变量的指针的常见问题。一旦函数返回,变量cvStr
将超出范围,因此将被破坏并释放它处理的内存(您使用scanReturn
指向的字符串)。这意味着scanReturn
将指向不再存在的东西,取消引用该指针将导致未定义的行为。
有两种可能的解决方案:将指向缓冲区的指针(及其长度)作为参数传递给函数,然后将字符串复制到该函数。或者动态分配内存,让调用者释放它。
您必须 malloc 内存(就像您已经做的那样),将字符串的内容复制到其中(不要忘记 null 终止它),然后返回您从 malloc 获得的指针(不要将其分配给另一个地址,您的函数将泄漏!)。
只是一个快速提示 - 不要添加与您的问题没有直接关联的标签 - 例如 VB.Net 标签。您可能认为向更广泛的受众展示您的问题是件好事,但是绝大多数 VB 人员对 c++ 一无所知。干杯
@DidierTrosset :因为他计划稍后在 VB.NET 中 P/Invoking 这个,在这种情况下,他需要一个可以编组为 .NET 类型的返回类型 (char*
-> @987654330 @)。
【参考方案1】:
一个可能的解决方案:
char* scanImage(char* fileDir)
std::string dir(fileDir); // dir is in the scope of scanImage
std::string cvStr = cvScan(dir); // cvStr is in the scope of scanImage
auto scanReturn = (char*)malloc(sizeof(char) * (cvStr.length() + 1)); // scanReturn will stay after you returned from scanImage, ensure it's big enough
strcpy(scanReturn, cvStr); // copy content of the (local) string cvStr to scanReturn
cout << "DLL Output: " << endl << scanReturn << endl;
return scanReturn; // return the POINTER to the memory, malloc gave us
http://www.cplusplus.com/reference/cstring/strcpy/ http://www.cplusplus.com/reference/cstdlib/malloc/
【讨论】:
是的!这就是解决方案!【参考方案2】:也许不是最佳解决方案,但您可以使用内置的std::copy()
method 将字符串复制到char*
。
char* scanReturn = new char[cvStr.size() + 1];
std::copy(cvStr.begin(), cvStr.end(), scanReturn);
scanReturn[str.size()] = '\0'; //Null-terminate the string.
return scanReturn;
这使您可以(更多)控制新分配的内存,但这也意味着您必须在使用完字符串后通过delete[]
自行释放内存(使用时可能会变得有点困难)它在 VB.NET 中)。
int main()
char * ret;
ret = scanImage("files/stu2/1.bmp");
cout << ret << endl;
delete[] ret; //Free the string's memory when you're no longer using it.
return 0;
【讨论】:
@nsssayom :哦,好吧,值得一试!如果您不创建变量而是直接调用return cvStr.c_str();
会怎样? (注意:您可以将返回类型更改为const char*
)
文森特,请不要提供错误的解决方案 - 这仍然会返回一个悬空指针。
@Wolfgang :你能解释一下吗?哪个指针“悬空”?我对 C++ 的内存管理不是很熟悉......(FWIW 我也在为答案进行更新,因为它对 OP 无论如何都不起作用)——编辑:哦等等,我想我明白了……const char*
仍然指向原始字符串,对吧?
@VisualVincent - 当然可以,请参阅cplusplus.com/reference/string/string/c_str :: c_str() 返回一个指向数组的指针,该数组包含字符串字符的空终止序列。该指针指向 std::string 的“内部数据结构”(保证顺序存储)——这意味着如果字符串超出范围,则指针无效。这样它就是一个悬空指针。【参考方案3】:
这个问题解决了。如果将来对任何人有帮助,请发布解决方案-
DLL 函数-
char * scanImage(char * fileDir)
string dir(fileDir);
string cvStr = cvScan(dir);
char * scanReturn;
scanReturn = (char*) CoTaskMemAlloc((cvStr.size() + 1) * sizeof(char));
strcpy(scanReturn, cvStr.c_str());
cout << "DLL Output: " << endl << scanReturn <<endl;
return scanReturn;
客户端功能-
int dll_client()
char * ret = scanImage("files/stu2/1.bmp");
cout << endl << ret << endl;
return 0;
【讨论】:
这会泄漏,dll_client 必须释放内存 scanImage 分配。带有 cvStr.c_str() 的 strcopy 不需要添加空终止符的额外行,c_str() 保证空终止符。 如何使用 dll_client 释放分配给 scanImage 的内存?只是free(scanImage);
? @Wolfgang
free 对应malloc,delete 对应new……看看cplusplus.com 的引用就知道了。都在那里!以上是关于C++ DLL char* 返回问题的主要内容,如果未能解决你的问题,请参考以下文章