从 dll 调用函数时分配大小无效
Invalid allocation size when calling a function from dll
我刚开始用dll,之前没遇到过这个问题,所以可能是dll连接不上。我有用 C++ 实现的 KMP 字符串匹配算法,我使用 dll 从 C# 调用它。
这是我的出口:
extern "C" __declspec (dllexport) const char* naive(const char* text, const char* str);
extern "C" __declspec (dllexport) const char* KMP(const char* text, const char* str);
我的导入:
[DllImport(@"dll_path", CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr KMP([MarshalAs(UnmanagedType.LPStr)] string text, [MarshalAs(UnmanagedType.LPStr)] string str);
从 c# 调用
string output = Marshal.PtrToStringAnsi(KMP(richTextBox1.Text, richTextBox2.Text));
和 c++ 函数:
const char* KMP(const char* text, const char* str)
{
int tL = strlen(text);
int sL = strlen(str);
/* Algorithm */
}
调用函数后立即抛出异常。所以我认为这不是代码实现。有线的事情是只有当第二个参数 (str) 中有一个 '\n' 新行时才会抛出它,无论具体在哪里。如果没有新行,它会正常运行。最让我困惑的是为什么只有第二个参数,两者的声明和使用都是相同的。我也实现了朴素算法,同样的故事。
我找到的所有答案都只是在数组或未声明变量的大小为负数时,但指针没有任何答案。但我怀疑它有什么相似之处,因为当我的搜索字符串(第二个参数(str))不包含换行符时,代码正常执行。
有什么想法吗?
谢谢前面的
编辑(函数体):
const char* KMP(const char* text, const char* str)
{
int tL = strlen(text);
int sL = strlen(str);
string match = "";
if (sL == 0 || tL == 0)
throw "both text and string must be larger than 0";
else if (sL > tL)
throw "the text must be longer than the string";
int tI = 0;
int col = 0, row = 0;
while (tI <= tL - sL)
{
int i = 0;
int tmpCol = -1;
int next = 1;
for (; i <= sL && text[i + tI] != '[=14=]'; i++)
{
if (text[i + tI] == '\n')
{
row++;
tmpCol++;
}
if (text[i + tI] == str[0] && next == 1 && i > 0)
next = i;
if (text[i + tI] != str[i])
break;
}
if (i == sL)
{
match += to_string(row) + ',' + to_string(col) + ';';
}
tI += next;
col = tmpCol > -1 ? tmpCol : col + next;
}
char* c = new char[match.length() - 1];
c[match.length() - 1] = '[=14=]';
for (int i = 0; i < match.length() - 1; i++)
c[i] = match[i];
return c;
}
只需更改您的代码以处理不匹配的情况,因为运行时无法分配 0-1 = 0xFFFFFFFFF
字节。现在我还更改了您的复制缓冲区分配和循环代码以避免覆盖(正如@HenkHoltermann 所指出的):
...
if (match.length() == 0)
return "No matches";
// Allocate for all chars + [=10=] except the last semicolon
char* c = new char[match.length()];
c[match.length() - 1] = '[=10=]';
// Copy all chars except the last semicolon
for (int i = 0; i < match.length() - 1; i++)
c[i] = match[i];
return c;
!它仍然没有复制最后一个分号,所以如果你需要它,那么你将不得不在缓冲区中再添加一个符号。
P.S.: 另外我发现您的代码存在一些问题:
- 您使用了 C++ 异常。虽然 CLR 会将它们捕获为 SEH(因为 VC++ 使用 SEH),但总的来说这仍然不是一个好主意 - Throwing C++ exceptions across DLL boundaries
- 您使用带符号
int
的长度 int tL = strlen(text);
和 strlen
returns 无符号 size_t
。这可能不是实际问题,但也不是正确的方法。
我刚开始用dll,之前没遇到过这个问题,所以可能是dll连接不上。我有用 C++ 实现的 KMP 字符串匹配算法,我使用 dll 从 C# 调用它。
这是我的出口:
extern "C" __declspec (dllexport) const char* naive(const char* text, const char* str);
extern "C" __declspec (dllexport) const char* KMP(const char* text, const char* str);
我的导入:
[DllImport(@"dll_path", CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr KMP([MarshalAs(UnmanagedType.LPStr)] string text, [MarshalAs(UnmanagedType.LPStr)] string str);
从 c# 调用
string output = Marshal.PtrToStringAnsi(KMP(richTextBox1.Text, richTextBox2.Text));
和 c++ 函数:
const char* KMP(const char* text, const char* str)
{
int tL = strlen(text);
int sL = strlen(str);
/* Algorithm */
}
调用函数后立即抛出异常。所以我认为这不是代码实现。有线的事情是只有当第二个参数 (str) 中有一个 '\n' 新行时才会抛出它,无论具体在哪里。如果没有新行,它会正常运行。最让我困惑的是为什么只有第二个参数,两者的声明和使用都是相同的。我也实现了朴素算法,同样的故事。
我找到的所有答案都只是在数组或未声明变量的大小为负数时,但指针没有任何答案。但我怀疑它有什么相似之处,因为当我的搜索字符串(第二个参数(str))不包含换行符时,代码正常执行。
有什么想法吗?
谢谢前面的
编辑(函数体):
const char* KMP(const char* text, const char* str)
{
int tL = strlen(text);
int sL = strlen(str);
string match = "";
if (sL == 0 || tL == 0)
throw "both text and string must be larger than 0";
else if (sL > tL)
throw "the text must be longer than the string";
int tI = 0;
int col = 0, row = 0;
while (tI <= tL - sL)
{
int i = 0;
int tmpCol = -1;
int next = 1;
for (; i <= sL && text[i + tI] != '[=14=]'; i++)
{
if (text[i + tI] == '\n')
{
row++;
tmpCol++;
}
if (text[i + tI] == str[0] && next == 1 && i > 0)
next = i;
if (text[i + tI] != str[i])
break;
}
if (i == sL)
{
match += to_string(row) + ',' + to_string(col) + ';';
}
tI += next;
col = tmpCol > -1 ? tmpCol : col + next;
}
char* c = new char[match.length() - 1];
c[match.length() - 1] = '[=14=]';
for (int i = 0; i < match.length() - 1; i++)
c[i] = match[i];
return c;
}
只需更改您的代码以处理不匹配的情况,因为运行时无法分配 0-1 = 0xFFFFFFFFF
字节。现在我还更改了您的复制缓冲区分配和循环代码以避免覆盖(正如@HenkHoltermann 所指出的):
...
if (match.length() == 0)
return "No matches";
// Allocate for all chars + [=10=] except the last semicolon
char* c = new char[match.length()];
c[match.length() - 1] = '[=10=]';
// Copy all chars except the last semicolon
for (int i = 0; i < match.length() - 1; i++)
c[i] = match[i];
return c;
!它仍然没有复制最后一个分号,所以如果你需要它,那么你将不得不在缓冲区中再添加一个符号。
P.S.: 另外我发现您的代码存在一些问题:
- 您使用了 C++ 异常。虽然 CLR 会将它们捕获为 SEH(因为 VC++ 使用 SEH),但总的来说这仍然不是一个好主意 - Throwing C++ exceptions across DLL boundaries
- 您使用带符号
int
的长度int tL = strlen(text);
和strlen
returns 无符号size_t
。这可能不是实际问题,但也不是正确的方法。