# Integral numeric types (C# reference)

The **integral numeric types** are a subset of the **simple types** and can be initialized with *literals*. All integral types are also value types. All integral numeric types support arithmetic, bitwise logical, comparison, and equality operators.

## Characteristics of the integral types

C# supports the following predefined integral types:

C# type/keyword | Range | Size | .NET type |
---|---|---|---|

`sbyte` |
-128 to 127 | Signed 8-bit integer | System.SByte |

`byte` |
0 to 255 | Unsigned 8-bit integer | System.Byte |

`short` |
-32,768 to 32,767 | Signed 16-bit integer | System.Int16 |

`ushort` |
0 to 65,535 | Unsigned 16-bit integer | System.UInt16 |

`int` |
-2,147,483,648 to 2,147,483,647 | Signed 32-bit integer | System.Int32 |

`uint` |
0 to 4,294,967,295 | Unsigned 32-bit integer | System.UInt32 |

`long` |
-9,223,372,036,854,775,808 to 9,223,372,036,854,775,807 | Signed 64-bit integer | System.Int64 |

`ulong` |
0 to 18,446,744,073,709,551,615 | Unsigned 64-bit integer | System.UInt64 |

In the preceding table, each C# type keyword from the leftmost column is an alias for the corresponding .NET type. They are interchangeable. For example, the following declarations declare variables of the same type:

```
int a = 123;
System.Int32 b = 123;
```

The default value of each integral type is zero, `0`

. Each of the integral types has the `MinValue`

and `MaxValue`

constants that provide the minimum and maximum value of that type.

Use the System.Numerics.BigInteger structure to represent a signed integer with no upper or lower bounds.

## Integral literals

Integral literals can be specified as *decimal literals*, *hexadecimal literals*, or *binary literals*. An example of each is shown below:

```
var decimalLiteral = 42;
var hexLiteral = 0x2A;
var binaryLiteral = 0b_0010_1010;
```

Decimal literals don't require any prefix. The `x`

or `X`

prefix signifies a *hexadecimal literal*. The `b`

or `B`

prefix signifies a *binary literal*. The declaration of `binaryLiteral`

demonstrates the use of `_`

as a *digit separator*. The digit separator can be used with all numeric literals. Binary literals and the digit separator `_`

are supported starting with C# 7.0.

### Literal suffixes

The `l`

or `L`

suffix specifies that the integral literal should be of the `long`

type. The `ul`

or `UL`

suffix specifies the `ulong`

type. If the `L`

suffix is used on a literal that is greater than 9,223,372,036,854,775,807 (the maximum value of `long`

), the value is converted to the `ulong`

type. If the value represented by an integral literal exceeds UInt64.MaxValue, a compiler error CS1021 occurs.

Note

You can use the lowercase letter "l" as a suffix. However, this generates a compiler warning because the letter "l" is easily confused with the digit "1." Use "L" for clarity.

### Type of an integral literal

If an integral literal has no suffix, its type is the first of the following types in which its value can be represented:

`int`

`uint`

`long`

`ulong`

You can convert an integral literal to a type with a smaller range than the default using either an assignment or a cast:

```
byte byteVariable = 42; // type is byte
var signedByte = (sbyte)42; // type is sbyte.
```

You can convert an integral literal to a type with a larger range than the default using either assignment, a cast, or a suffix on the literal:

```
var unsignedLong = 42UL;
var longVariable = 42L;
ulong anotherUnsignedLong = 42;
var anotherLong = (long)42;
```

## Conversions

There's an implicit conversion (called a *widening conversion*) between any two integral types where the destination type can store all values of the source type. For example, there's an implicit conversion from `int`

to `long`

because the range of `int`

values is a proper subset of `long`

. There are implicit conversions from a smaller unsigned integral type to a larger signed integral type. There's also an implicit conversion from any integral type to any floating-point type. There's no implicit conversion from any signed integral type to any unsigned integral type.

You must use an explicit cast to convert one integral type to another integral type when an implicit conversion is not defined from the source type to the destination type. This is called a *narrowing conversion*. The explicit case is required because the conversion can result in data loss.

## See also

## Feedback

Loading feedback...