Why Data Types Are Important
Data types are especially important in C# because it is a strongly typed language. This means
that all operations are type-checked by the compiler for type compatibility. Illegal operations
will not be compiled. Thus, strong type-checking helps prevent errors and enhances reliability.
To enable strong type-checking, all variables, expressions, and values have a type. There is no
concept of a “typeless” variable, for example. Furthermore, the type of a value determines what
operations are allowed on it. An operation allowed on one type might not be allowed on another.
C#’s Value Types
C# contains two general categories of built-in data types: value types and reference types. The
difference between the two types is what a variable contains. For a value type, a variable holds
an actual value, such 101 or 98.6. For a reference type, a variable holds a reference to the value.
---------- Post added at 09:06 PM ---------- Previous post was at 09:05 PM ----------
The most commonly used reference type is the class, and a discussion of classes and reference
types is deferred until later. The value types are described here.
At the core of C# are the 13 value types shown in Table 2-1. Collectively, these are
referred to as the simple types. They are called simple types because they consist of a single
value. (In other words, they are not a composite of two or more values.) They form the
foundation of C#’s type system, providing the basic, low-level data elements upon which
a program operates. The simple types are also sometimes referred to as primitive types.
C# strictly specifies a range and behavior for each simple type. Because of portability
requirements and to support mixed-language programming, C# is uncompromising on this
account. For example, an int is the same in all execution environments. There is no need to
rewrite code to fit a specific platform. While strictly specifying the size of the simple types
may cause a small loss of performance in some environments, it is necessary in order to
achieve portability.
NOTE
In addition to the simple types, C# defines three other categories of value types. These
are enumerations, structures, and nullable types, all of which are described later in
this book.
Integers
C# defines nine integer types: char, byte, sbyte, short, ushort, int, uint, long, and ulong.
However, the char type is primarily used for representing characters, and it is discussed later
---------- Post added at 09:11 PM ---------- Previous post was at 09:06 PM ----------
Type Meaning
bool Represents true/false values
byte 8-bit unsigned integer
char Character
decimal Numeric type for financial calculations
double Double-precision floating point
float Single-precision floating point
int Integer
long Long integer
sbyte 8-bit signed integer
short Short integer
uint Unsigned integer
ulong Unsigned long integer
ushort Unsigned short integer
Table 2-1 The C# Simple Types
---------- Post added at 09:12 PM ---------- Previous post was at 09:11 PM ----------
in this chapter. The remaining eight integer types are used for numeric calculations. Their bitwidth
and ranges are shown here:
Type Width in Bits Range
byte 8 0 to 255
sbyte 8 –128 to 127
short 16 –32,768 to 32,767
ushort 16 0 to 65,535
int 32 –2,147,483,648 to 2,147,483,647
uint 32 0 to 4,294,967,295
long 64 –9,223,372,036,854,775,808 to 9,223,372,036,854,775,807
ulong 64 0 to 18,446,744,073,709,551,615
As the table shows, C# defines both signed and unsigned versions of the various integer
types. The difference between signed and unsigned integers is in the way the high-order bit of
the integer is interpreted. If a signed integer is specified, the C# compiler will generate code
that assumes the high-order bit of an integer is to be used as a sign flag. If the sign flag is 0,
the number is positive; if it is 1, the number is negative. Negative numbers are almost always
represented using the two’s complement approach. In this method, all bits in the number are
reversed, and then 1 is added to this number.
Signed integers are important for a great many algorithms, but they have only half the
absolute magnitude of their unsigned relatives. For example, as a short, here is 32,767:
0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
---------- Post added at 09:12 PM ---------- Previous post was at 09:12 PM ----------
For a signed value, if the high-order bit were set to 1, the number would then be interpreted
as –1 (assuming the two’s complement format). However, if you declared this to be a ushort,
then when the high-order bit was set to 1, the number would become 65,535.
Probably the most commonly used integer type is int. Variables of type int are often
employed to control loops, to index arrays, and for general-purpose integer math. When you
need an integer that has a range greater than int, you have many options. If the value you want
to store is unsigned, you can use uint. For large signed values, use long. For large unsigned
values, use ulong.
Here is a program that computes the number of cubic inches contained in a cube that is
1 mile long on each side. Because this value is so large, the program uses a long variable to
hold it.
// Compute the number of cubic inches in 1 cubic mile.
using System;
class Inches {
static void Main() {
long ci;
long im;
im = 5280 * 12;
ci = im * im * im;
Console.WriteLine("There are " + ci +
" cubic inches in cubic mile.");
}
}
Here is the output from the program:
There are 254358061056000 cubic inches in cubic mile.
Clearly, the result could not have been held in an int or uint variable.
The smallest integer types are byte and sbyte. The byte type is an unsigned value between
0 and 255. Variables of type byte are especially useful when working with raw binary data,
such as a byte stream produced by some device. For small signed integers, use sbyte. Here is
an example that uses a variable of type byte to control a for loop that produces the summation
of the number 100:
---------- Post added at 09:13 PM ---------- Previous post was at 09:12 PM ----------
// Use byte.
using System;
class Use_byte {
static void Main() {
byte x;
int sum;
sum = 0;
for(x = 1; x <= 100; x++)
sum = sum + x;
Console.WriteLine("Summation of 100 is " + sum);
}
}
The output from the program is shown here:
Summation of 100 is 5050
Since the for loop runs only from 0 to 100, which is well within the range of a byte, there is no
need to use a larger type variable to control it. Of course, byte could not have been used to hold
the result of the summation because 5050 is far outside its range. This is why sum is an int.
When you need an integer that is larger than a byte or sbyte but smaller than an int or
uint, use short or ushort.
---------- Post added at 09:13 PM ---------- Previous post was at 09:13 PM ----------
Floating-Point Types
As explained in Chapter 1, the floating-point types can represent numbers that have fractional
components. There are two kinds of floating-point types, float and double, which represent
single- and double-precision numbers, respectively. The type float is 32 bits wide and has a
range of 1.5E–45 to 3.4E+38. The double type is 64 bits wide and has a range of 5E–324 to
1.7E+308.
Of the two, double is the most commonly used. One reason for this is that many of the
math functions in C#’s class library (which is the .NET Framework library) use double values.
For example, the Sqrt( ) method (which is defined by the System.Math class) returns a double
value that is the square root of its double argument. Here, Sqrt( ) is used to compute the length
of the hypotenuse given the lengths of the two opposing sides:
/*
Use the Pythagorean theorem to find the length of the hypotenuse
given the lengths of the two opposing sides.
*/
using System;
class Hypot {
static void Main() {
double x, y, z;
x = 3;
y = 4;
z = Math.Sqrt(x*x + y*y);
Console.WriteLine("Hypotenuse is " + z);
}
}
The output from the program is shown here:
Hypotenuse is 5
Here’s another point about the preceding example. As mentioned, Sqrt( ) is a member of
the Math class. Notice how Sqrt( ) is called; it is preceded by the name Math. This is similar
to the way Console precedes WriteLine( ). Although not all standard methods are called by
specifying their class name first, several are.
The decimal Type
Perhaps the most interesting C# numeric type is decimal, which is intended for use in
monetary calculations. The decimal type utilizes 128 bits to represent values within the range
1E–28 to 7.9E+28. As you may know, normal floating-point arithmetic is subject to a variety
---------- Post added at 09:14 PM ---------- Previous post was at 09:13 PM ----------
of rounding errors when it is applied to decimal values. The decimal type eliminates these
errors and can accurately represent up to 28 decimal places (or 29 places, in some cases).
This ability to represent decimal values without rounding errors makes it especially useful for
computations that involve money.
Here is a program that uses the decimal type in a financial calculation. The program
computes a balance after interest has been applied.
// Use the decimal type in a financial calculation.
using System;
class UseDecimal {
static void Main() {
decimal balance;
decimal rate;
// Compute new balance.
balance = 1000.10m;
rate = 0.1m;
balance = balance * rate + balance;
Console.WriteLine("New balance: $" + balance);
}
}
The output from this program is shown here:
New balance: $1100.110