C# 中size_t的暗坑
阿新 • • 發佈:2020-04-17
最近在接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++