Skip to content

Instantly share code, notes, and snippets.

@BinToss
Last active July 17, 2022 00:50
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save BinToss/39934d36c1016adf6f6123d8874ec08c to your computer and use it in GitHub Desktop.
Save BinToss/39934d36c1016adf6f6123d8874ec08c to your computer and use it in GitHub Desktop.
C/C++ code often employs bitfields and unions (overlapping data) to save bandwidth and conserve memory. This is an example of a bitfield implemented in C#
/// bitfield experiment
/// <summary>C definition</summary>
/// <remarks>
/// <para>
/// C bitfield unions' maximum size is defined by the
/// size of the largest Type in the bitfield union.
/// </para>
/// <para>
/// Each field in the union defines their bit count
/// with the syntax "Type Name : Int", using the colon
/// to signify that the following integer is the
/// amount of bits to occupy.
/// </para>
/// <c>
/// typedef struct _PH_WORK_QUEUE_ENVIRONMENT
/// {
/// LONG BasePriority : 6; // Base priority increment
/// ULONG IoPriority : 3; // I/O priority hint
/// ULONG PagePriority : 3; // Page/memory priority
/// ULONG ForceUpdate : 1; // Always set priorities regardless of cached values
/// ULONG SpareBits : 19;
/// } PH_WORK_QUEUE_ENVIRONMENT, *PPH_WORK_QUEUE_ENVIRONMENT;
/// </c>
/// </remarks>
[StructLayout(LayoutKind.Explicit, Size = 4)]
internal struct PH_WORK_QUEUE_ENVIRONMENT
{
[FieldOffset(0)] private uint _;
public PH_WORK_QUEUE_ENVIRONMENT()
{
_ = 0;
}
/// struct/enum definitions do not add to the struct's unmanaged size :)
/// We use structs instead of enums here so we don't need to convert to/from enum and uint types.
/// These constants are not necessary, but they do provide shorthands for longer values e.g. 19-bit sequential bitmask.
private struct os // Offset
{
public const int BP = 0; // occupies s.BP bits
public const int IP = s.BP; // occupies s.IP bits
public const int PP = IP + s.IP; // occupies s.PP bits
public const int FU = PP + s.PP; // occupies s.FU bits
public const int SB = FU + s.FU;
private struct s // bits occupied at each offset
{
public const int BP = 6;
public const int IP = 3;
public const int PP = 3;
public const int FU = 1;
public const int SB = 19;
}
}
private struct bm // sequential bitmask
{
public const uint BP = 0b11_1111;
public const uint IP = 0b111;
public const uint PP = 0b111;
public const uint FU = 0b1;
public const uint SB = 0b111_1111_1111_1111_1111;
}
/// <summary>Base priority increment (6 bits)</summary>
public int BasePriority
{
get => (int)((_ >> os.BP) & bm.BP);
set => _ = (((uint)value & bm.BP) << os.BP) | (_ & ~(bm.BP << os.BP));
}
/// <summary>I/O priority hint (3 bits)</summary>
public uint IoPriority
{
get => (_ >> os.IP) & bm.IP;
set => _ = ((value & bm.IP) << os.IP) | (_ & ~(bm.IP << os.IP));
}
/// <summary>Page/memory priority (3 bits)</summary>
public uint PagePriority
{
get => (_ >> os.PP) & bm.PP;
set => _ = ((value & bm.PP) << os.PP) | (_ & ~(bm.PP << os.PP));
}
/// <summary>Always set priorities regardless of cached values (1 bit)</summary>
public uint ForceUpdate
{
get => (_ >> os.FU) & bm.FU;
set => _ = ((value & bm.FU) << os.FU) | (_ & ~(bm.FU << os.FU));
}
public uint SpareBits
{
get => (_ >> os.SB) & bm.SB;
set => _ = ((value & bm.SB) << os.SB) | (_ & ~(bm.SB << os.SB));
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment