[英]Matching the memory size of C# struct with C++ struct
我正在嘗試創建從C#結構到C ++和CUDA中非托管代碼的自動轉換。 不幸的是,我似乎無法創建匹配的結構。 結構:
// C#
[StructLayout(LayoutKind.Sequential)]
struct DebugComponent
{
public float4 Float4;
public float Float;
}
// C++
struct CPP_DebugComponent
{
float4 Float4;
float Float;
};
使用C#調用將結構的大小計算為20個字節:
var size = System.Runtime.InteropServices.Marshal.SizeOf<DebugComponent>();
但是,在使用sizeof的C ++中,相同的結構為32個字節:
auto size = sizeof(CPP_DebugComponent);
我相信差異源自float4結構的定義方式。 CUDA中的float4的定義將其對齊為16個字節:
// C++
struct __device_builtin__ __builtin_align__(16) float4
{
float x, y, z, w;
};
// For similar results without the CUDA definition, you can use:
// struct __align__(16) float4
因此,在單個float中添加了12個字節的填充。 在C#中,沒有這樣的對齊方式,導致編譯器選擇4字節的壓縮。 為了完整起見,C#中的float4定義(來自ManagedCuda):
// C#
public struct float4
{
public float x;
public float y;
public float z;
public float w;
}
我知道我可以通過指定以下屬性來在C#中人為地重新創建正確大小的結構:
[StructLayout(LayoutKind.Sequential, Size = 32)]
struct DebugComponent { ... }
但是對於自動代碼生成,這需要了解結構中所有類型的總和以及有關打包和填充的一些假設。 看來我無法使用StructLayoutAttribute.Pack擴展結構。
我也知道我可以使用以下示例更改C ++代碼中的包裝:
#pragma pack(1)
但是我寧願避免這種解決方案,因為填充會導致性能顯着提高。
我的問題:我可以模仿非托管填充/打包的行為,以使C#結構在內存大小方面與C ++結構保持一致嗎?
是否有很好的替代方法來對齊結構,同時牢記性能?
以上所有代碼示例均在Windows,Visual Studio 2017上運行並在x64上編譯。
我認為, 最好的方法是在規范中聲明一個結構大小的數組。 C#或C ++對象應將元素從緩沖區復制到其數據成員中。
這是最可移植的,可以處理C#和C ++成員之間的填充。 由於填充,v表和其他內容,C#和C ++類不適用於將1:1與數據格式映射。 從緩沖區復制還可以處理字符串類和類中的其他非POD類型。
還研究“序列化”。
結構/結構成員的填充和對齊是AFAIK,不屬於C ++標准且與實現無關。 意思是,一旦更改了C ++編譯器,您將獲得不同的布局(或可能得到)。 這也是Nvidia保證CUDA僅可與某些給定的編譯器一起工作的原因之一。
為了使此代碼轉換自動運行,您需要使用StructLayout
選項在C#中模擬C ++編譯器:遵循與C ++編譯器相同的規則。 對於一般情況,這不是不可能,但可能很難進行推導...另一方面,對於給定結構這樣的簡單結構,應該可以推導C ++編譯器對齊規則。 例如,一個基本規則是,最大的成員確定整個結構的對齊方式。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.