gpt4 book ai didi

c# - 寻求处理具有重叠字段的结构构造函数的最佳方法

转载 作者:IT王子 更新时间:2023-10-28 23:36:06 25 4
gpt4 key购买 nike

我创建了一个自定义结构来处理将被编码到 GPU 的 RGBA 值。

在我的类型中,我将单独的 R、G、B 和 A 组件保存为字节值,并重叠一个 32 位无符号整数 (Uint32) 以轻松传递和分配打包值。我知道这个概念很明显,但这里有一个很好的结构示例:

[StructLayout(LayoutKind.Explicit, Size = 4)]
public struct RGBA
{
[FieldOffset(0)]
public uint32 PackedValue;

[FieldOffset(0)]
public byte R;

[FieldOffset(1)]
public byte G;

[FieldOffset(2)]
public byte B;

[FieldOffset(3)]
public byte A;
}

由于 c# 处理结构的方式,每个字段必须在定义的任何构造函数中显式分配。就我而言,这意味着由于字段重叠,我必须在任何构造函数中分配两次值。

我可以使用:

public RGBA(uint packed value)
{
R = G = B = A = 0; // initialize all to defaults before assigning packed value
PackedValue = packedValue;
}

public RGBA(byte r, byte g, byte b, byte a)
{
PackedValue = 0; // initialize to default before assigning components
R = r;
G = g;
B = b;
A = a;
}

或者我可以像这样首先在每个构造函数上调用基本构造函数:

public RGBA(uint packedValue) : this()
{
PackedValue = packedValue;
}

public RGBA(byte r, byte g, byte b, byte a) : this()
{
R = r;
G = g;
B = b;
A = a;
}

由于这是用于图形代码,因此性能至关重要,我正在尝试找到在这种情况下处理构建的最佳方法。使用第一个示例似乎是两个示例中开销最小的,因为虽然它涉及分配所有字段两次(一次用于 PackedValue,一次用于 R、G、B 和 A 字段),但另一个示例涉及分配所有值 3 次(两次在默认构造函数中,一次在定义的构造函数中)。

有没有办法让编译器识别这些字段重叠,并且如果 PackedValue 被分配,则不需要明确分配 R、G、B 和 A,反之亦然?我假设这可以通过手动调整生成的 IL 来完成,但我想知道是否有一种方法可以直接在 c# 中更优化地处理这个问题。

有什么想法吗?

最佳答案

来自 here :

结构成员会自动初始化为其默认值。因此,无需在任一构造函数中将它们中的任何一个初始化为其默认值。

但是,这不适用于您的情况。它仅适用于非重叠字段,并且仅在您使用默认构造函数时才有效。无论如何,请参阅答案的最后一部分以获取基于此的替代方案。

查看单参数构造函数的 IL 代码,我们可以看到编译器什么都不做(没有优化,这是默认设置的 Release模式):

.method public hidebysig specialname rtspecialname 
instance void .ctor(uint32 packedValue) cil managed
{
// Code size 42 (0x2a)
.maxstack 6
.locals init ([0] uint8 CS$0$0000,
[1] uint8 CS$0$0001,
[2] uint8 CS$0$0002)
IL_0000: ldarg.0
IL_0001: ldarg.0
IL_0002: ldarg.0
IL_0003: ldarg.0
IL_0004: ldc.i4.0
IL_0005: dup
IL_0006: stloc.0
IL_0007: stfld uint8 ConsoleApplication2.Program/RGBA::A
IL_000c: ldloc.0
IL_000d: dup
IL_000e: stloc.1
IL_000f: stfld uint8 ConsoleApplication2.Program/RGBA::B
IL_0014: ldloc.1
IL_0015: dup
IL_0016: stloc.2
IL_0017: stfld uint8 ConsoleApplication2.Program/RGBA::G
IL_001c: ldloc.2
IL_001d: stfld uint8 ConsoleApplication2.Program/RGBA::R
IL_0022: ldarg.0
IL_0023: ldarg.1
IL_0024: stfld uint32 ConsoleApplication2.Program/RGBA::PackedValue
IL_0029: ret
} // end of method RGBA::.ctor

经过@usr的建议,jitting后看起来一样(这也是 Release模式,成员单独分配):

007400B5  call        750586FE  
007400BA mov eax,dword ptr [ebp-8]
007400BD mov byte ptr [eax],0
G = 0;
007400C0 mov eax,dword ptr [ebp-8]
007400C3 mov byte ptr [eax+1],0
B = 0;
007400C7 mov eax,dword ptr [ebp-8]
007400CA mov byte ptr [eax+2],0
A = 0;
007400CE mov eax,dword ptr [ebp-8]
007400D1 mov byte ptr [eax+3],0
PackedValue = packedValue;
007400D5 mov eax,dword ptr [ebp-8]
007400D8 mov edx,dword ptr [ebp-4]
007400DB mov dword ptr [eax],edx

也许对它进行基准测试是现在最好的方法。或者,使用默认构造函数并在获得结构实例后手动分配 PackedValue。在这种情况下,文章中描述的默认行为将适用。

var rgba = new RGBA { PackedValue = 2556 };

var rgba = new RGBA();
rgba.PackedValue = 2556;

关于c# - 寻求处理具有重叠字段的结构构造函数的最佳方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25089293/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com