1. 程式人生 > WINDOWS開發 >C# 中size_t的暗坑

C# 中size_t的暗坑

最近在接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++