Table of Contents

Preserve exact enum values

An enum gives names to integer values, but data written by another version of a program may contain a number your current layout does not name. That number is still valid binary data.

CStructSharp returns EnumValueResult (from CStructSharp.Values) rather than narrowing every enum to a C# int. The result retains:

  • the enum declaration and optional member name;
  • the exact mathematical value;
  • the raw stored bits;
  • the backing width and signedness; and
  • the backing storage type.

This matters for unsigned 32-bit and 64-bit values that do not fit in a signed 32-bit integer.

Read an unknown value

The executable example declares one known value:

enum state : uint32 {
    Known = 1
};

struct root {
    state value;
};

It then reads FF FF FF FF:

private static void PreserveEnum()
{
    var layout = new CStruct("enum state : uint32 { Known = 1 }; struct root { state value; };");
    var value = (EnumValueResult)layout.ReadValue(new byte[] { 0xFF, 0xFF, 0xFF, 0xFF }, "root.value")!;
    Equal(new BigInteger(uint.MaxValue), value.Value);
    Equal(null, value.Name);
    Equal(32, value.BitWidth);
    True(!value.IsSigned, "uint32 enum should be unsigned.");
}

The result has:

Value    = 4294967295
RawBits  = 0xFFFFFFFF
BitWidth = 32
IsSigned = false
Name     = null

Check Name before branching on a declared member. A null name means “this number is not declared here,” not “the input is corrupt.”

Write enums without narrowing

For a faithful read-modify-write cycle, keep and pass the original EnumValueResult. You can also write:

  • a declared member name;
  • a CLR integral value that fits the backing type;
  • a BigInteger;
  • an invariant decimal integer string; or
  • a compatible object carrying consistent enum metadata.

Contradictory metadata, a number outside the backing range, a boolean, or a fractional value produces CStructWriteException. The writer never truncates high bits to make the value fit.

An enum without an explicit backing type uses unsigned one-byte storage. This differs from C compilers, which may choose an integer representation according to ABI rules. State the backing type when the binary format depends on a particular width.

Map to a CLR enum

ReadValue<MyEnum> can map the exact numeric payload to a C# enum. CLR enums can hold values that have no named member, so the conversion does not make an unknown payload invalid. If your application must preserve width, signedness, or raw-bit details, read EnumValueResult instead of discarding that information.

Common mistakes are casting through int, treating Name == null as a read error, assuming the default backing is a C int, or serializing only the display name after receiving an unknown value.

See Enums in the layout language for expressions and supported backing types.