C# tutorials > Core C# Fundamentals > Basics and Syntax > What are the primitive data types in C#?

What are the primitive data types in C#?

In C#, primitive data types are the fundamental building blocks for storing data. They are predefined types provided by the C# language itself. Understanding these types is crucial for writing efficient and reliable code. They directly represent data values and are not composed of other types. They're also sometimes referred to as built-in types.

Overview of Primitive Data Types

C# provides a rich set of primitive data types, each designed to store specific kinds of values. These can be broadly categorized into:

  • Integral Types: Represent whole numbers (positive, negative, and zero).
  • Floating-Point Types: Represent numbers with fractional parts.
  • Decimal Type: Suitable for financial and monetary calculations requiring high precision.
  • Boolean Type: Represents logical values (true or false).
  • Character Type: Represents a single Unicode character.

Integral Types

Integral types are used to store whole numbers. C# offers several integral types, each with a different range of values:

  • byte: Unsigned 8-bit integer. Range: 0 to 255.
  • sbyte: Signed 8-bit integer. Range: -128 to 127.
  • short: Signed 16-bit integer. Range: -32,768 to 32,767.
  • ushort: Unsigned 16-bit integer. Range: 0 to 65,535.
  • int: Signed 32-bit integer. Range: -2,147,483,648 to 2,147,483,647.
  • uint: Unsigned 32-bit integer. Range: 0 to 4,294,967,295.
  • long: Signed 64-bit integer. Range: -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807.
  • ulong: Unsigned 64-bit integer. Range: 0 to 18,446,744,073,709,551,615.

byte age = 30; // Stores an unsigned 8-bit integer (0 to 255)
sbyte temperature = -10; // Stores a signed 8-bit integer (-128 to 127)
short year = 2023; // Stores a signed 16-bit integer (-32,768 to 32,767)
ushort port = 8080; // Stores an unsigned 16-bit integer (0 to 65,535)
int count = 1000; // Stores a signed 32-bit integer (-2,147,483,648 to 2,147,483,647)
uint population = 5000000; // Stores an unsigned 32-bit integer (0 to 4,294,967,295)
long bigNumber = 1234567890123; // Stores a signed 64-bit integer (-9,223,372,036,854,775,808 to 9,223,372,036,854,775,807)
ulong veryBigNumber = 9876543210987654321; // Stores an unsigned 64-bit integer (0 to 18,446,744,073,709,551,615)

Floating-Point Types

Floating-point types are used to store numbers with fractional parts:

  • float: Single-precision floating-point number (32-bit). Append 'f' or 'F' to the numeric literal. Offers approximately 7 digits of precision.
  • double: Double-precision floating-point number (64-bit). The default floating-point type in C#. Offers approximately 15-17 digits of precision.

float price = 99.99f; // Stores a single-precision floating-point number
double pi = 3.14159265359; // Stores a double-precision floating-point number

Decimal Type

The decimal type is specifically designed for financial and monetary calculations where high precision is essential. It uses a 128-bit data type.

  • decimal: High-precision decimal number (128-bit). Append 'm' or 'M' to the numeric literal. Offers 28-29 significant digits.

decimal salary = 50000.50m; // Stores a high-precision decimal number

Boolean Type

The bool type represents logical values, which can be either true or false.

bool isLoggedIn = true; // Stores a boolean value (true or false)

Character Type

The char type is used to store a single Unicode character. It is a 16-bit value.

char initial = 'J'; // Stores a single Unicode character

Memory Footprint

Each primitive type consumes a specific amount of memory. The size (in bytes) varies based on the type:

  • byte: 1 byte
  • sbyte: 1 byte
  • short: 2 bytes
  • ushort: 2 bytes
  • int: 4 bytes
  • uint: 4 bytes
  • long: 8 bytes
  • ulong: 8 bytes
  • float: 4 bytes
  • double: 8 bytes
  • decimal: 16 bytes
  • bool: Typically 1 byte (implementation-dependent)
  • char: 2 bytes

Understanding the memory footprint helps in optimizing memory usage, especially when dealing with large datasets.

When to Use Them

Choosing the right data type is crucial for efficient and accurate code:

  • Use int for most integer values unless you have a specific need for a smaller or larger range.
  • Use double for general-purpose floating-point numbers.
  • Use decimal for financial calculations to avoid rounding errors.
  • Use bool for representing true/false conditions.
  • Use char for storing single characters.
  • Use byte when memory optimization is critical and the value range is within 0-255 (e.g., representing pixel color components).

Best Practices

Here are some best practices when working with primitive data types:

  • Choose the smallest data type that can accurately represent the data to save memory.
  • Use descriptive variable names to indicate the purpose of the data.
  • Be aware of potential overflow issues when working with integral types.
  • Use decimal for financial calculations to ensure accuracy.
  • Understand the limitations of floating-point types regarding precision.

FAQ

  • What is the difference between `float` and `double`?

    float is a single-precision floating-point type (32-bit), while double is a double-precision floating-point type (64-bit). double offers more precision and a wider range than float. double is generally the default choice unless you have specific memory constraints.
  • Why use `decimal` instead of `double` for monetary values?

    The decimal type provides higher precision and avoids rounding errors that can occur with double when representing decimal fractions. This makes it suitable for financial and monetary calculations where accuracy is paramount.
  • What happens if I assign a value larger than the maximum value of an `int`?

    If you assign a value larger than the maximum value of an int, an overflow exception may occur, or the value might wrap around to a negative number (depending on compile-time vs. runtime behavior and compiler settings). It's important to validate input and choose a data type that can accommodate the expected range of values.
  • What are the signed and unsigned integer?

    Signed integers (e.g., int, short) can represent both positive and negative numbers, while unsigned integers (e.g., uint, ushort) can only represent non-negative numbers (zero and positive values). Unsigned integers effectively double the maximum positive value that can be stored compared to their signed counterparts, by not using half of the value range to store negative numbers.