C# 中size_t的暗坑
程序员文章站
2022-05-04 11:49:34
最近在接SDK,在写DllImport遇到一个神奇的暗坑 export代码和DLLImport DLL是64位,测试代码如下 结果惊奇的发现sb = NULL 换了段测试代码 发现sb2的数据是正常的,sb1依旧是NUll 和同事研究了一下,最后发现是DllImport写得不对 换成以下写法就正常了 ......
最近在接sdk,在写dllimport遇到一个神奇的暗坑
export代码和dllimport
#if defined(_win32) || defined(_win64) #define __dllexport__ __declspec(dllexport) #else #define __dllexport__ #endif extern "c" { __dllexport__ void init(size_t* requiredsize,char* buff) { .... } }
[dllimport("acsdk")] public static extern void init(ref int requiredsize);
dll是64位,测试代码如下
int a = 1; stringbuilder sb = new stringbuilder(1024); init(ref a, sb); print(a);print(sb);
结果惊奇的发现sb = null
换了段测试代码
int a = 1; stringbuilder sb1 = new stringbuilder(1024); stringbuilder sb2 = new stringbuilder(1024); init(ref a, sb2); print(a);print(sb1);print(sb2);
发现sb2的数据是正常的,sb1依旧是null
和同事研究了一下,最后发现是dllimport写得不对
换成以下写法就正常了
[dllimport("acsdk")] public static extern void init(ref uintptr requiredsize);
导致这个bug的原因是因为size_t的跨平台性,c#下于它匹配的数据类型是uintptr,同样可以做到32位系统是4字节,64位系统是8字节,而且都是unsigned int
原来的写法之所以会出现异常奇怪的bug是因为c++的方法会将requiredsize置空后再赋值。
而c#下由于a和sb数据是连续的,2个加起来字节数才能和size_t对等,结果导致了sb也被置空,真是危险的c++