通过 dll 边界的 C 字符串
C string through dll boundaries
我们需要return C 字符串以安全的方式通过 dll 边界!我们该怎么做?
我的想法:
extern "C" __declspec(dllexport) const char *const Api
{
...
static const char *output = result.c_str();
return output;
}
您的示例代码中返回了一个指针,但它指向的内存区域可能不常驻。
如果结果变量 (std::string?) 在堆栈上,它会在函数 returns 时被销毁并且返回的指针将悬空——当然不是你想要的。
执行此操作的安全方法是对响应进行 strdup(),但随后调用者将负责释放 C 字符串。卸载 DLL 意味着返回的指针将悬空,除非它指向堆变量。
最简单的安全方法是
extern "C"
__declspec(dllexport)
size_t Api
(char* dest,
size_t dest_size)
{
if (dest)
strncpy(dest, str, dest_size);
return strlen(str);
}
另一个安全的方法是
extern "C"
__declspec(dllexport)
void Api
(void (*callback)(const char*))
{
callback(str);
}
返回 malloc'd/new' 的内存并不是 100% 安全的,因为 DLL 和主程序可以 link 到不同的运行时并使用不同的堆。如果是这种情况,调用者只能通过在 DLL 中调用 free/delete 来 free/delete 内存(并且 DLL 必须包装那些并导出包装器)。麻烦了。
返回静态内存不是 100% 安全的,因为调用者可能会存储指针并卸载 DLL,在这种情况下指针会悬空。
返回自动记忆当然是100%不安全
我们需要return C 字符串以安全的方式通过 dll 边界!我们该怎么做?
我的想法:
extern "C" __declspec(dllexport) const char *const Api
{
...
static const char *output = result.c_str();
return output;
}
您的示例代码中返回了一个指针,但它指向的内存区域可能不常驻。
如果结果变量 (std::string?) 在堆栈上,它会在函数 returns 时被销毁并且返回的指针将悬空——当然不是你想要的。
执行此操作的安全方法是对响应进行 strdup(),但随后调用者将负责释放 C 字符串。卸载 DLL 意味着返回的指针将悬空,除非它指向堆变量。
最简单的安全方法是
extern "C"
__declspec(dllexport)
size_t Api
(char* dest,
size_t dest_size)
{
if (dest)
strncpy(dest, str, dest_size);
return strlen(str);
}
另一个安全的方法是
extern "C"
__declspec(dllexport)
void Api
(void (*callback)(const char*))
{
callback(str);
}
返回 malloc'd/new' 的内存并不是 100% 安全的,因为 DLL 和主程序可以 link 到不同的运行时并使用不同的堆。如果是这种情况,调用者只能通过在 DLL 中调用 free/delete 来 free/delete 内存(并且 DLL 必须包装那些并导出包装器)。麻烦了。
返回静态内存不是 100% 安全的,因为调用者可能会存储指针并卸载 DLL,在这种情况下指针会悬空。
返回自动记忆当然是100%不安全