Bitwise Operations with Flags Enums in C

In C#, a flags enum is an enumeration type treated as a bit field, allowing a single variable to store multiple distinct states or options simultaneously. This article explains how to define a flags enum using the [Flags] attribute and values mapped to powers of two. It also demonstrates how to manipulate these values efficiently using bitwise operators—specifically the OR (|), AND (&), NOT (~), and XOR (^) operators, as well as the built-in HasFlag method.

Defining a Flags Enum

By default, an enum in C# represents a single distinct value. Adding the [Flags] attribute signals that the enum can be treated as a collection of bits. To ensure individual values do not overlap in binary representation, each member must be assigned a unique power of two (1, 2, 4, 8, 16, etc.) or defined using the binary literal or bit-shift syntax.

[Flags]
public enum FileAccessPermissions
{
    None    = 0,      // 0000
    Read    = 1 << 0, // 0001 (1)
    Write   = 1 << 1, // 0010 (2)
    Execute = 1 << 2, // 0100 (4)
    Delete  = 1 << 3  // 1000 (8)
}

The [Flags] attribute does not alter the underlying data or enforce assignment rules; its primary runtime effect is altering the behavior of the .ToString() method to display comma-separated flag names instead of a raw integer.

Combining Flags (Bitwise OR)

To assign multiple values to a single variable, use the bitwise OR (|) operator. The OR operator combines the bits of each operand, setting a bit to 1 if it is present in either value.

FileAccessPermissions userPermissions = FileAccessPermissions.Read | FileAccessPermissions.Write;
// Binary: 0001 | 0010 = 0011 (Value: 3)
// userPermissions.ToString() outputs: "Read, Write"

Checking for a Flag (Bitwise AND)

To test whether a specific flag is set, you can use the bitwise AND (&) operator or the Enum.HasFlag method.

The bitwise AND operator masks the bits, returning a non-zero value if the specific flag exists:

bool canRead = (userPermissions & FileAccessPermissions.Read) == FileAccessPermissions.Read;

Alternatively, use HasFlag:

bool canWrite = userPermissions.HasFlag(FileAccessPermissions.Write);

While HasFlag is more readable, direct bitwise AND operations are faster and preferred in performance-critical code paths.

Removing a Flag (Bitwise AND with NOT)

To remove a flag from an existing combination, combine the bitwise NOT (~) and bitwise AND (&) operators. The bitwise NOT operator inverts the target bits, and the AND operator unsets the target bit while preserving all others.

// Remove Write permission
userPermissions &= ~FileAccessPermissions.Write;
// Binary: 0011 & ~0010 => 0011 & 1101 = 0001 (Read)

Toggling a Flag (Bitwise XOR)

To invert the state of a flag (turning it off if it is on, or on if it is off), use the bitwise XOR (^) operator.

// Toggle Execute permission on
userPermissions ^= FileAccessPermissions.Execute;

// Toggle Execute permission off
userPermissions ^= FileAccessPermissions.Execute;

Summary of Operators

  • Bitwise OR (|): Combines multiple flags together.
  • Bitwise AND (&): Checks if one or more flags are present.
  • Bitwise NOT (~): Inverts all bits, primarily used with AND to strip a flag.
  • Bitwise XOR (^): Toggles a flag between active and inactive.