C# Bug/Issue? Struct-alignment

  • C#
  • .NET (FX) 4.5–4.8

Es gibt 6 Antworten in diesem Thema. Der letzte Beitrag () ist von Facebamm.

    C# Bug/Issue? Struct-alignment

    Hii :D


    Ich hab ein Kleines uns unschönes problem und zwar wir mein Struct falsch ausgerichtet wird trz. [StructLayout(LayoutKind.Sequential, ... )]

    Aber nur wenn ich uint nutz start bool.
    Ich weiß bool ist 1Byte groß, deswegen nutz ich FieldOffset um den Bool an die richtige stelle zu rücken.

    Aber was ich nicht verstehe, warum ändert C# meine Reinfolge trz Attributen.

    Foto's
    Spoiler anzeigen

    Mit uint


    Mit bool




    C#-Quellcode

    1. [StructLayout(LayoutKind.Sequential, Pack = 1)]
    2. public unsafe struct VkPhysicalDeviceProperties2
    3. {
    4. [MarshalAs(UnmanagedType.U4)]
    5. public VkStructureType sType;
    6. public void* pNext;
    7. public VkPhysicalDeviceProperties properties;
    8. }


    C#-Quellcode

    1. [StructLayout(LayoutKind.Sequential)]
    2. public unsafe struct VkPhysicalDeviceProperties
    3. {
    4. public VkVersion apiVersion;
    5. public uint driverVersion;
    6. public uint vendorID;
    7. public uint deviceID;
    8. public VkPhysicalDeviceType deviceType;
    9. public fixed sbyte deviceName[VK_MAX_PHYSICAL_DEVICE_NAME_SIZE];
    10. public fixed byte pipelineCacheUUID[VK_UUID_SIZE];
    11. [MarshalAs(UnmanagedType.Struct)]
    12. public VkPhysicalDeviceLimits limits;
    13. public VkPhysicalDeviceSparseProperties sparseProperties;
    14. }


    VkPhysicalDeviceLimits - Kann ignoriert werden, jede änderung brachte auch keine änderung im Aufbau
    Spoiler anzeigen

    C#-Quellcode

    1. [StructLayout(LayoutKind.Sequential)]
    2. public unsafe struct VkPhysicalDeviceLimits
    3. {
    4. public uint maxImageDimension1D;
    5. public uint maxImageDimension2D;
    6. public uint maxImageDimension3D;
    7. public uint maxImageDimensionCube;
    8. public uint maxImageArrayLayers;
    9. public uint maxTexelBufferElements;
    10. public uint maxUniformBufferRange;
    11. public uint maxStorageBufferRange;
    12. public uint maxPushConstantsSize;
    13. public uint maxMemoryAllocationCount;
    14. public uint maxSamplerAllocationCount;
    15. public VkDeviceSize bufferImageGranularity;
    16. public VkDeviceSize sparseAddressSpaceSize;
    17. public uint maxBoundDescriptorSets;
    18. public uint maxPerStageDescriptorSamplers;
    19. public uint maxPerStageDescriptorUniformBuffers;
    20. public uint maxPerStageDescriptorStorageBuffers;
    21. public uint maxPerStageDescriptorSampledImages;
    22. public uint maxPerStageDescriptorStorageImages;
    23. public uint maxPerStageDescriptorInputAttachments;
    24. public uint maxPerStageResources;
    25. public uint maxDescriptorSetSamplers;
    26. public uint maxDescriptorSetUniformBuffers;
    27. public uint maxDescriptorSetUniformBuffersDynamic;
    28. public uint maxDescriptorSetStorageBuffers;
    29. public uint maxDescriptorSetStorageBuffersDynamic;
    30. public uint maxDescriptorSetSampledImages;
    31. public uint maxDescriptorSetStorageImages;
    32. public uint maxDescriptorSetInputAttachments;
    33. public uint maxVertexInputAttributes;
    34. public uint maxVertexInputBindings;
    35. public uint maxVertexInputAttributeOffset;
    36. public uint maxVertexInputBindingStride;
    37. public uint maxVertexOutputComponents;
    38. public uint maxTessellationGenerationLevel;
    39. public uint maxTessellationPatchSize;
    40. public uint maxTessellationControlPerVertexInputComponents;
    41. public uint maxTessellationControlPerVertexOutputComponents;
    42. public uint maxTessellationControlPerPatchOutputComponents;
    43. public uint maxTessellationControlTotalOutputComponents;
    44. public uint maxTessellationEvaluationInputComponents;
    45. public uint maxTessellationEvaluationOutputComponents;
    46. public uint maxGeometryShaderInvocations;
    47. public uint maxGeometryInputComponents;
    48. public uint maxGeometryOutputComponents;
    49. public uint maxGeometryOutputVertices;
    50. public uint maxGeometryTotalOutputComponents;
    51. public uint maxFragmentInputComponents;
    52. public uint maxFragmentOutputAttachments;
    53. public uint maxFragmentDualSrcAttachments;
    54. public uint maxFragmentCombinedOutputResources;
    55. public uint maxComputeSharedMemorySize;
    56. public fixed uint maxComputeWorkGroupCount[3];
    57. public uint maxComputeWorkGroupInvocations;
    58. public fixed uint maxComputeWorkGroupSize[3];
    59. public uint subPixelPrecisionBits;
    60. public uint subTexelPrecisionBits;
    61. public uint mipmapPrecisionBits;
    62. public uint maxDrawIndexedIndexValue;
    63. public uint maxDrawIndirectCount;
    64. public float maxSamplerLodBias;
    65. public float maxSamplerAnisotropy;
    66. public uint maxViewports;
    67. public fixed uint maxViewportDimensions[2];
    68. public fixed float viewportBoundsRange[2];
    69. public uint viewportSubPixelBits;
    70. public nuint minMemoryMapAlignment;
    71. public VkDeviceSize minTexelBufferOffsetAlignment;
    72. public VkDeviceSize minUniformBufferOffsetAlignment;
    73. public VkDeviceSize minStorageBufferOffsetAlignment;
    74. public int minTexelOffset;
    75. public uint maxTexelOffset;
    76. public int minTexelGatherOffset;
    77. public uint maxTexelGatherOffset;
    78. public float minInterpolationOffset;
    79. public float maxInterpolationOffset;
    80. public uint subPixelInterpolationOffsetBits;
    81. public uint maxFramebufferWidth;
    82. public uint maxFramebufferHeight;
    83. public uint maxFramebufferLayers;
    84. public VkSampleCountFlags framebufferColorSampleCounts;
    85. public VkSampleCountFlags framebufferDepthSampleCounts;
    86. public VkSampleCountFlags framebufferStencilSampleCounts;
    87. public VkSampleCountFlags framebufferNoAttachmentsSampleCounts;
    88. public uint maxColorAttachments;
    89. public VkSampleCountFlags sampledImageColorSampleCounts;
    90. public VkSampleCountFlags sampledImageIntegerSampleCounts;
    91. public VkSampleCountFlags sampledImageDepthSampleCounts;
    92. public VkSampleCountFlags sampledImageStencilSampleCounts;
    93. public VkSampleCountFlags storageImageSampleCounts;
    94. public uint maxSampleMaskWords;
    95. //[MarshalAs(UnmanagedType.Bool)]
    96. public uint timestampComputeAndGraphics;
    97. public float timestampPeriod;
    98. public uint maxClipDistances;
    99. public uint maxCullDistances;
    100. public uint maxCombinedClipAndCullDistances;
    101. public uint discreteQueuePriorities;
    102. public fixed float pointSizeRange[2];
    103. public fixed float lineWidthRange[2];
    104. public float pointSizeGranularity;
    105. public float lineWidthGranularity;
    106. //[MarshalAs(UnmanagedType.Bool)]
    107. public uint strictLines;
    108. //[MarshalAs(UnmanagedType.Bool)]
    109. public uint standardSampleLocations;
    110. public VkDeviceSize optimalBufferCopyOffsetAlignment;
    111. public VkDeviceSize optimalBufferCopyRowPitchAlignment;
    112. public VkDeviceSize nonCoherentAtomSize;
    113. }


    Struct mit dem es geht .
    Spoiler anzeigen

    C#-Quellcode

    1. [StructLayout(LayoutKind.Explicit, Size = 20)]
    2. public readonly struct VkPhysicalDeviceSparseProperties
    3. {
    4. [FieldOffset(0)]
    5. public readonly uint residencyStandard2DBlockShape;
    6. [FieldOffset(4)]
    7. public readonly uint residencyStandard2DMultisampleBlockShape;
    8. [FieldOffset(8)]
    9. public readonly uint residencyStandard3DBlockShape;
    10. [FieldOffset(12)]
    11. public readonly uint residencyAlignedMipSize;
    12. [FieldOffset(16)]
    13. public readonly uint residencyNonResidentStrict;
    14. }


    Struct mit dem es nicht geht.
    Spoiler anzeigen

    C#-Quellcode

    1. [StructLayout(LayoutKind.Explicit, Size = 20)]
    2. public readonly struct VkPhysicalDeviceSparseProperties
    3. {
    4. [MarshalAs(UnmanagedType.Bool)]
    5. [FieldOffset(0)]
    6. public readonly bool residencyStandard2DBlockShape;
    7. [MarshalAs(UnmanagedType.Bool)]
    8. [FieldOffset(4)]
    9. public readonly bool residencyStandard2DMultisampleBlockShape;
    10. [FieldOffset(8)]
    11. [MarshalAs(UnmanagedType.Bool)]
    12. public readonly bool residencyStandard3DBlockShape;
    13. [FieldOffset(12)]
    14. [MarshalAs(UnmanagedType.Bool)]
    15. public readonly bool residencyAlignedMipSize;
    16. [FieldOffset(16)]
    17. [MarshalAs(UnmanagedType.Bool)]
    18. public readonly bool residencyNonResidentStrict;
    19. }

    Bei welchem Feld änderst du zwischen bool und uint und welches Feld verschiebt sich dadurch?
    Kannst du ein Minimalbeispiel erstellen, das das Problem reproduziert? Also am besten nur zwei Felder.

    Übrigens Marshal.SizeOf(typeof(bool)) ist 4, nicht 1! Wenn du dich auf LayoutKind.Sequential verlässt, wird das sicher so angewendet.
    "Luckily luh... luckily it wasn't poi-"
    -- Brady in Wonderland, 23. Februar 2015, 1:56
    Desktop Pinner | ApplicationSettings | OnUtils
    Also ich hab mal ein exmapel aufgesetzt ... mit klein wurde das nicht so ;(
    Exampel: IssueProject.zip

    Ich muss auch gestehen, das ich das verhalten echt schwer beschreiben kann, weil ich nicht verstehe wie das geht?Der C#-Compiler müsste ja hingehen und das Struct packen aber das darf er nicht an der stellen, wegen dem Attribut über meinem Struct. Da hast du recht, aber sizeof(bool) ist 1.

    Einzel Datein
    Spoiler anzeigen

    Program.cs
    Vulkan.cs
    IssueProject.csproj

    XML-Quellcode

    1. <Project Sdk="Microsoft.NET.Sdk">
    2. <PropertyGroup>
    3. <OutputType>Exe</OutputType>
    4. <TargetFramework>net5.0</TargetFramework>
    5. <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
    6. </PropertyGroup>
    7. </Project>

    Facebamm schrieb:

    Aber was ich nicht verstehe, warum ändert C# meine Reinfolge trz Attributen.


    Ja, da bin ich auch schon einmal auf die Klappe geflogen. Sobald ich in einem Struct fixed für Arrays verwende, schiebt er dies immer an das Ende und die anderen Felder rücken nach. Die Dokumentation ist an dieser Stelle meiner Meinung nach zu schwach oder sogar gar nicht richtig.

    The CLI spec states that the "sequential" layout attribute is sequential based on the fields in the logical metadata table (not the source code itself)
    StructLayout Sequential not working for class

    und

    LayoutKind.Sequential not followed when substruct has LayoutKind.ExplicitAsk Question

    Also immer LayoutKind.Explicit mit FieldOffset nutzen, wenn du das richtige Layout der Struktur selber bestimmen musst. Ich denke, dass dir eines der untern Structs jetzt die ganze Kette zerhaut.
    Okay, Sobald ich in einem Struct fixed für Arrays verwende wusste ich nicht ...

    aber wie bestimme ich in AnyCPU die Größe eines void* bei LayoutKind.Explicit ? Oo

    und warum geht es mit fixed bei Uint? Oo

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „Facebamm“ ()

    Facebamm schrieb:

    aber wie bestimme ich in AnyCPU die Größe eines void* bei LayoutKind.Explicit ? Oo


    Soweit ich weiß, gar nicht. Ich habe für solche Fälle bis jetzt immer 2 Structs angelegt. ​MyValueStruct32 und ​MyValueStruct64. Du hast dann praktisch für 32 und 64 Bit alles doppelt. Das ist Mist, aber ich kenne da keine andere Lösung.