2

I have a question.

I am currently studying Flag among Enum functions. And then I was wondering, what is the maximum size that I can designate as Enum Flag?

I'm currently marking the flag as below.

A = 1 << 0,
B = 1 << 1,
C = 1 << 2,
ZZZ = 1 << MaxSize(?)

I'm curious about the value of Max size.

Thank you for reading it, and there may be grammatical errors because it is translated. :-)

DevSon
  • 51
  • 6
  • 2
    The biggest backing-type for an `enum` is `Int64` and `UInt64`, so you can have _at most_ 64 distinct individual bits as flags - but you can have synonyms (enum members with the same value but different names) and arbitrary bitwise combinations as their own members. – Dai Sep 01 '21 at 00:58
  • @Dai Then is it possible until ZZZ = 1 < < 64? – DevSon Sep 01 '21 at 02:19
  • 2
    Actually `1<<63`. `1<<64` would be `0`. – D Stanley Sep 01 '21 at 02:32
  • 2
    @DStanley no .. `1 << 31`. An `int` has 32 bits so after that you are just starting over. The bitshift operators only work on and with `int` so you will never go beyond `1<<31` – derHugo Sep 01 '21 at 07:57
  • @derHugo _"The bitshift operators only work on and with int"_ - uhh, what? I can use `<<` and `>>` with `Int64` operands on the right-hand just fine, and shift by 33 or 63 bits: https://dotnetfiddle.net/MlfZ6A – Dai Sep 22 '22 at 14:32
  • @Dai well, yes .. but not if you wrote `1 << 64` .. that's what I mean .. because these are still `int` and will return `int` – derHugo Sep 23 '22 at 19:30

2 Answers2

3

What follows are random thoughts of mine in no particular order:


  • In .NET, an enum type is essentially a set of named-constants for the enum's underlying-type.
    • Though the C# compiler does not allow implicit conversion between an enum's values and its underlying-type (except for 0).
  • This is documented in the .NET Common Language Infrastructure specification: ECMA-335, 5th edition (2010), page 34.
  • In C#, an enum can use any of the of .NET's built-in integer types as an underlying-type (as of .NET 5 in 2021, we're still limited to the same 8 integer bytes as we were back in 2001, but we might get a real Int128 eventually, but that's still years away):
    • Byte and SByte (1 octet: 8 bits, values 0-255 and -128 to 127 respectively).
    • UInt16 and Int16 (2 bytes aka 2 octets: 16 bits, values 0-65535 and -32768 to 32767 respectively).
    • UInt32 and Int32 (4 bytes, 32 bits, etc).
    • UInt64 and Int64 (8 bytes, 64 bits, etc).
    • (I believe that the .NET spec does technically allow Boolean/bool to be used as an enum underlying-type, but C# does not allow this).

It's immediately obvious that both Int64 and UInt64 (aka long and ulong for people who are allergic to the shift-key) offer the widest "space" for bit values: there's 64 bits to play with, after all - while the other underlying-types only grant you 32, 16, or a measly 8 bits.


There is no limit on the number of members in an enum, but obviously enums with smaller underlying-types will exhaust their set of possible values sooner than bigger types and will eventually repeat themselves.

enum types can have multiple members with different names that share the same integer value, however internally the CLR has no way of knowing one from the other.


what is the maximum size that I can designate as Enum Flag?

If you're referring to the underlying-type then the straightforward answer is either Int64 (long) or UInt64 (ulong).

If you're asking about the maximum value that an enum member can have, then that would be YourUnderlyingType.MaxValue, for example:

enum IntSizedEnum : Int32
{
    LargestValue = Int32.MaxValue
}

enum BiggerEnum : UInt64
{
    EvenLargerLargestValue = UInt64.MaxValue
}

If you're asking about the number of bits set, then if you use Int64 or UInt64 you can get 64 bits, or individual flags - and even define them on a bit-by-bit basis with bit-literals, for example:

enum BiggerEnum : UInt64
{
    All64Bits = 0b_11111111_11111111_11111111_11111111_11111111_11111111_11111111_11111111
}

With flags, you can go a bit crazy:

[Flags]
enum BiggerEnum : UInt64
{
    FlagsCombination = Bit_32 | Bit_33 | Bit_34,

    Bit_0  = 0b00000000_00000000_00000000_00000000_00000000_00000000_00000000_00000001,
    Bit_1  = 0b00000000_00000000_00000000_00000000_00000000_00000000_00000000_00000010,
    Bit_2  = 0b00000000_00000000_00000000_00000000_00000000_00000000_00000000_00000100,
    Bit_3  = 0b00000000_00000000_00000000_00000000_00000000_00000000_00000000_00001000,
    Bit_4  = 0b00000000_00000000_00000000_00000000_00000000_00000000_00000000_00010000,
    Bit_5  = 0b00000000_00000000_00000000_00000000_00000000_00000000_00000000_00100000,
    Bit_6  = 0b00000000_00000000_00000000_00000000_00000000_00000000_00000000_01000000,
    Bit_7  = 0b00000000_00000000_00000000_00000000_00000000_00000000_00000000_10000000,
    Bit_8  = 0b00000000_00000000_00000000_00000000_00000000_00000000_00000001_00000000,
    Bit_9  = 0b00000000_00000000_00000000_00000000_00000000_00000000_00000010_00000000,
    Bit_10 = 0b00000000_00000000_00000000_00000000_00000000_00000000_00000100_00000000,
    Bit_11 = 0b00000000_00000000_00000000_00000000_00000000_00000000_00001000_00000000,
    Bit_12 = 0b00000000_00000000_00000000_00000000_00000000_00000000_00010000_00000000,
    Bit_13 = 0b00000000_00000000_00000000_00000000_00000000_00000000_00100000_00000000,
    Bit_14 = 0b00000000_00000000_00000000_00000000_00000000_00000000_01000000_00000000,
    Bit_15 = 0b00000000_00000000_00000000_00000000_00000000_00000000_10000000_00000000,
    Bit_16 = 0b00000000_00000000_00000000_00000000_00000000_00000001_00000000_00000000,
    Bit_17 = 0b00000000_00000000_00000000_00000000_00000000_00000010_00000000_00000000,
    Bit_18 = 0b00000000_00000000_00000000_00000000_00000000_00000100_00000000_00000000,
    Bit_19 = 0b00000000_00000000_00000000_00000000_00000000_00001000_00000000_00000000,
    Bit_20 = 0b00000000_00000000_00000000_00000000_00000000_00010000_00000000_00000000,
    Bit_21 = 0b00000000_00000000_00000000_00000000_00000000_00100000_00000000_00000000,
    Bit_22 = 0b00000000_00000000_00000000_00000000_00000000_01000000_00000000_00000000,
    Bit_23 = 0b00000000_00000000_00000000_00000000_00000000_10000000_00000000_00000000,
    Bit_24 = 0b00000000_00000000_00000000_00000000_00000001_00000000_00000000_00000000,
    Bit_25 = 0b00000000_00000000_00000000_00000000_00000010_00000000_00000000_00000000,
    Bit_26 = 0b00000000_00000000_00000000_00000000_00000100_00000000_00000000_00000000,
    Bit_27 = 0b00000000_00000000_00000000_00000000_00001000_00000000_00000000_00000000,
    Bit_28 = 0b00000000_00000000_00000000_00000000_00010000_00000000_00000000_00000000,
    Bit_29 = 0b00000000_00000000_00000000_00000000_00100000_00000000_00000000_00000000,
    Bit_30 = 0b00000000_00000000_00000000_00000000_01000000_00000000_00000000_00000000,
    Bit_31 = 0b00000000_00000000_00000000_00000000_10000000_00000000_00000000_00000000,
    Bit_32 = 0b00000000_00000000_00000000_00000001_00000000_00000000_00000000_00000000,
    Bit_33 = 0b00000000_00000000_00000000_00000010_00000000_00000000_00000000_00000000,
    Bit_34 = 0b00000000_00000000_00000000_00000100_00000000_00000000_00000000_00000000,
    Bit_35 = 0b00000000_00000000_00000000_00001000_00000000_00000000_00000000_00000000,
    Bit_36 = 0b00000000_00000000_00000000_00010000_00000000_00000000_00000000_00000000,
    Bit_37 = 0b00000000_00000000_00000000_00100000_00000000_00000000_00000000_00000000,
    Bit_38 = 0b00000000_00000000_00000000_01000000_00000000_00000000_00000000_00000000,
    Bit_39 = 0b00000000_00000000_00000000_10000000_00000000_00000000_00000000_00000000,
    Bit_40 = 0b00000000_00000000_00000001_00000000_00000000_00000000_00000000_00000000,
    Bit_41 = 0b00000000_00000000_00000010_00000000_00000000_00000000_00000000_00000000,
    Bit_42 = 0b00000000_00000000_00000100_00000000_00000000_00000000_00000000_00000000,
    Bit_43 = 0b00000000_00000000_00001000_00000000_00000000_00000000_00000000_00000000,
    Bit_44 = 0b00000000_00000000_00010000_00000000_00000000_00000000_00000000_00000000,
    Bit_45 = 0b00000000_00000000_00100000_00000000_00000000_00000000_00000000_00000000,
    Bit_46 = 0b00000000_00000000_01000000_00000000_00000000_00000000_00000000_00000000,
    Bit_47 = 0b00000000_00000000_10000000_00000000_00000000_00000000_00000000_00000000,
    Bit_48 = 0b00000000_00000001_00000000_00000000_00000000_00000000_00000000_00000000,
    Bit_49 = 0b00000000_00000010_00000000_00000000_00000000_00000000_00000000_00000000,
    Bit_50 = 0b00000000_00000100_00000000_00000000_00000000_00000000_00000000_00000000,
    Bit_51 = 0b00000000_00001000_00000000_00000000_00000000_00000000_00000000_00000000,
    Bit_52 = 0b00000000_00010000_00000000_00000000_00000000_00000000_00000000_00000000,
    Bit_53 = 0b00000000_00100000_00000000_00000000_00000000_00000000_00000000_00000000,
    Bit_54 = 0b00000000_01000000_00000000_00000000_00000000_00000000_00000000_00000000,
    Bit_55 = 0b00000000_10000000_00000000_00000000_00000000_00000000_00000000_00000000,
    Bit_56 = 0b00000001_00000000_00000000_00000000_00000000_00000000_00000000_00000000,
    Bit_57 = 0b00000010_00000000_00000000_00000000_00000000_00000000_00000000_00000000,
    Bit_58 = 0b00000100_00000000_00000000_00000000_00000000_00000000_00000000_00000000,
    Bit_59 = 0b00001000_00000000_00000000_00000000_00000000_00000000_00000000_00000000,
    Bit_60 = 0b00010000_00000000_00000000_00000000_00000000_00000000_00000000_00000000,
    Bit_61 = 0b00100000_00000000_00000000_00000000_00000000_00000000_00000000_00000000,
    Bit_62 = 0b01000000_00000000_00000000_00000000_00000000_00000000_00000000_00000000,
    Bit_63 = 0b10000000_00000000_00000000_00000000_00000000_00000000_00000000_00000000
}
// Usage:
BiggerEnum value = default;
value |= BiggerEnum.Bit_32 | BiggerEnum.Bit_33 | BiggerEnum.Bit_34;

Console.WriteLine( value == BiggerEnum.FlagsCombination ); // true
Console.WriteLine( value ); // 30064771072

...but you really shouldn't be doing that.

Dai
  • 141,631
  • 28
  • 261
  • 374
1

In the way you want to use it with bitshifting it would be

1 << 31

which is

-2147483648

and well an int has exactly 32 bits so if you do

1 << 32

meaning you take the value 1

00000000 00000000 00000000 00000001

and now shift all the bits 32 times to the left it just results again in 1 or

1 << 0

It would be no use to change the underlying enum type to e.g. ulong. At least not using bitshift operators since the bitshift operator always only can bitshift int values (see e.g. here).


If you really want to go crazy look at Dai's answer! Manually you can actually expand the flag to use the undelying type ulong and have up to 64 values.

derHugo
  • 83,094
  • 9
  • 75
  • 115