2009-06-25 38 views
31

我正在寻找一种方法将一些数据填充到跨越DLL边界的字符串中。因为我们使用不同的编译器,所以我们所有的dll接口都是简单的char *。直接写入std :: string内部缓冲区

是否有正确的方法将指针传入dll函数,以便它能够直接填充字符串缓冲区?

string stringToFillIn(100, '\0'); 
FunctionInDLL(stringToFillIn.c_str(), stringToFillIn.size()); // definitely WRONG! 
FunctionInDLL(const_cast<char*>(stringToFillIn.data()), stringToFillIn.size()); // WRONG? 
FunctionInDLL(&stringToFillIn[0], stringToFillIn.size());  // WRONG? 
stringToFillIn.resize(strlen(stringToFillIn.c_str())); 

看起来最有前途的一个是& stringToFillIn [0],但一个正确的方式来做到这一点,因为你会认为字符串::数据()== &串[0]?看起来不一致。

还是更吞下一个额外的配置和回避的问题:

vector<char> vectorToFillIn(100); 
FunctionInDLL(&vectorToFillIn[0], vectorToFillIn.size()); 
string dllGaveUs(&vectorToFillIn[0]); 

回答

23

我不确定该标准是否保证std::string中的数据存储为char*。我能想到的最简单的方法是使用一个std::vector,这是保证存储在内存中的连续块的数据:

std::vector<char> buffer(100); 
FunctionInDLL(&buffer[0], buffer.size()); 
std::string stringToFillIn(&buffer[0]); 

当然这需要对数据进行复制两次,这是一个位效率低下。

+5

在效率方面,如果启动使用std ::矢量作为缓冲,你将遇到一种不同类型的性能问题,其中向量的每个元素都被逐一初始化。如果你保留一个32K的缓冲区(这并不是那么重要),你将花费大量的CPU时间来初始化这个缓冲区。如果你只是需要一个连续的内存块,你会更好的简单地使用一个数组new new char []将它与std :: unique_ptr或其他一些RAII模式结合起来,你可以很好地去,但不要使用std ::除非你绝对需要初始化每个元素。 – 2013-03-07 12:55:49

+2

使用http://stackoverflow.com/questions/11149665/c-vector-that-doesnt-initialize-its-members中的矢量技巧。 – 2013-06-06 16:26:03

+0

“我不确定标准保证`std :: string`中的数据存储为`char *`。”它有保证。 `std :: string`使用`char`。 http://en.cppreference.com/w/cpp/string/basic_string – cambunctious 2016-07-13 20:09:37

3

我没有能力建立的std :: string和船舶的指针跨越DLL边界的内部缓冲区。相反,我会使用一个简单的字符缓冲区(静态或动态分配)。在对dll的调用返回后,我会让一个std :: string接管结果。让被调用者在内部的类缓冲区中写入,感觉是错误的。

0

std :: string的标准部分是API和一些行为,而不是实现的内存布局。

因此,如果你使用不同的编译器,你不能假设它们是相同的,所以你需要传输实际的数据。正如其他人所说的传输字符的和推入新的std ::字符串。

20

经过大量的阅读和挖掘,我发现string :: c_str和string :: data可以合法地返回一个指向缓冲区的指针,该缓冲区与字符串本身的存储方式无关。例如,字符串可能存储在段中。写入这些缓冲区会对字符串的内容产生未定义的影响。

此外,string :: operator []不应该用于获取指向字符序列的指针 - 它应该只用于单个字符。这是因为指针/数组等价不适用于字符串。

对此非常危险的是,它可以在某些实现上工作,但在未来的某个日期突然中断没有明显的原因。

因此,像其他人所说的那样,唯一安全的方法是避免直接写入字符串缓冲区并使用向量,将指针传递给第一个元素,然后从向量中分配字符串从dll函数返回。

+27

C++ 0x正在改变字符串以使用连续内存 – Patrick 2009-06-25 11:11:59

0

你们都已经解决了连续性问题(即它不能保证是连续的),所以我只提到分配/释放点。我在过去的问题中,我已经在dll中分配了内存(即,dll返回了一个字符串),导致了破坏时(dll外部)出现错误。要解决这个问题,你必须确保你的分配器和内存池在dll边界上是一致的。它会为你节省一些调试时间;)

2

考虑到帕特里克的评论,我会说,直接写入std :: string是很方便/高效的。我会用&s.front()得到char *,就像这个MEX例如:

#include "mex.h" 
#include <string> 
void mexFunction(
    int nlhs, 
    mxArray *plhs[], 
    int nrhs, 
    const mxArray *prhs[] 
) 
{ 
    std::string ret; 
    int len = (int)mxGetN(prhs[0]); 
    ret.reserve(len+1); 
    mxGetString(prhs[0],&ret.front(),len+1); 
    mexPrintf(ret.c_str()); 
} 
9

在C++ 98你不应该改变由string::c_str()string::data()返回的缓冲区。另外,正如其他答案中所解释的那样,您不应该使用string::operator[]来获取指向字符序列的指针 - 它只能用于单个字符。

从C++ 11开始,字符串使用连续的内存,因此您可以使用&string[0]来访问内部缓冲区。

3

只要C++ 11给出的连续存储器担保,在生产实践中,这“哈克”的方法是非常流行:

std::string stringToFillIn(100, 0); 
FunctionInDLL(stringToFillIn.data(), stringToFillIn.size()); 
相关问题