簡體   English   中英

將C#結構的內存大小與C ++結構匹配

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM