c++中的字符串
Strings in c++?
我的问题是,我在DLL中有一些函数,其中一些函数例如:
#include <string>
using namespace std;
extern "C" __declspec(dllexport) string __cdecl encryption(string s)
{
return s;
}
每当我尝试从c#调用这个函数时,下面是我使用的代码:
[DllImport("Packer.dll", EntryPoint = "encryption")]
static extern string encryption(string s);
我得到一个错误:调用PInvoke函数'Packer'使堆栈不平衡。这可能是因为托管的PInvoke签名与非托管的目标签名不匹配。检查PInvoke签名的调用约定和参数是否与目标非托管签名匹配。
我猜我得到这个错误是因为我没有正确的函数声明谁能指导我如何解决这个问题,提前感谢
std::string
不能与PInvoke一起使用,因为c++没有为其对象提供ABI,这需要正确地清理堆栈,复制对象等。这是c++最大的痛苦之一。
你必须使用char*
指针和普通的C api。简单地说,PInvoke不能在c++中工作。
我相信你已经知道,c++ std::string
实际上是一个模板。只有当模板被实例化时(如本例中的std::basic_string<char>
),该类型对象的确切布局和方法的签名才由c++编译器确定。
不幸的是,只有 c++编译器可以访问所有相关信息(如模板源代码)来做出这些决定。这就是为什么即使在不同的c++编译器之间,模板等非C特性通常也不能"转移"的原因,更不用说c++和c#了。
此外,c++名称通常以特定于c++编译器的方式进行"修改"。
你必须改变你的原生方法的签名,这样它就变成了一个"纯"C函数:
- 通过将函数声明为
extern "C"
(您已经这样做了)来确保没有c++名称混淆。 - 使用
char*
参数代替std::string
- 返回
char*
结果而不是std::string
,但要非常小心如何做。 - 确保您的
DllImportAttribute.CallingConvention
与c中的__cdecl
,__stdcall
或__fastcall
匹配。
这里的问题是,您使用的是c#不知道如何封送的STL string
类。这里有两个选项:
- 重构你的c++代码以使用
char *
缓冲区。或者写一个包装器或重载或其他使用char *
而不是string
的东西。 - 为c++函数编写一个c++/CLI包装器,该包装器使用
System::String
并在内部调用STL字符串版本。
如果内存可用,如果您没有指定其他方式,p/Invoke将假设调用约定为__stdcall
。如果是这样,将__cdecl
更改为__stdcall
应该可以解决第一个问题。正如@Adam Rosenfield指出的那样,您可能还需要传递并返回char const *
,而不是string
。几乎可以肯定,c#和c++对于字符串的构成有一些不同的想法。