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* 返回问题的主要内容,如果未能解决你的问题,请参考以下文章

C#从返回char指针的c++函数中获取字符串/字符值

关于delphi调用C++的DLL中char*参数的问题

C++ DLL 字符参数

用C++封装了Halcon的算法,返回值为Hobject类型,在C#中调用dll怎么用Hobject类型的返回值。

在 c++ 程序中使用 Java DLL

如何在 c# dllimport 中指定 c++ Variant 返回类型