
Advanced C 1992
.pdf
Data Types, Constants,CVariables,Cand Arrays CC C C
C2C C
2 C C C
C C C
C C C
Data Types, Constants,
Variables, and Arrays
The C language offers a number of data types, which can be used for constants, variables, and arrays. This chapter helps you become more familiar with data objects and how to use them.
Data Types
The C language supports a number of data types, all of which are necessary in writing programs. Because most CPUs generally support these data types directly, it is unnecessary for the compiler to convert the data types into the types the CPU understands. In addition to the standard types, new data types are needed, which are often unique to a given application, and C provides the mechanisms to create and use types of data created by the programmer.
19

Part I • Honing Your C Skills
The basic data types as they are defined by the ANSI standard are listed in Table 2.1. They are all that are needed when simpler applications are created (and are generally adequate for many of the more complex programs).
Table 2.1. C’s data types.
Type |
Size |
Description |
char
int
float
double
1 byte |
Used for characters or integer variables. |
2 or 4 bytes |
Used for integer values. |
4 bytes |
Floating-point numbers. |
8 bytes |
Floating-point numbers. |
In addition to these data types, some of them may be used with a modifier that affects the characteristics of the data object. These modifiers are listed in Table 2.2.
Table 2.2. C’s data type modifiers.
Modifier |
Description |
long |
Forces a type int to be 4 bytes (32 bits) long and forces a type |
|
double to be larger than a double (but the actual size is imple- |
|
mentation defined). Cannot be used with short. |
short |
Forces a type int to be 2 bytes (16 bits) long. Cannot be used |
|
with long. |
unsigned |
Causes the compiler (and CPU) to treat the number as con- |
|
taining only positive values. Because a 16-bit signed integer can |
|
hold values between –32,768 and 32,767, an unsigned integer |
|
can hold values between 0 and 65,535. The unsigned modifier |
|
can be used with char, long, and short (integer) types. |
|
|
Each of the data types (and their modifiers) has a minimum and maximum value (see Table 2.3). Check your compiler documentation because some compilers extend
20

Data Types, Constants, Variables, and Arrays |
C C C |
|
C2C |
|
C C C |
|
C |
these values. Be careful not to assume that a variable created as int is either 16 bits or 32 bits. Different compilers, on different computers, may default the size of an int variable to either size, depending on the CPU’s default integer size. If you must know the size of the variable, be sure you specify either long or short when you create it.
When you are entering constants, determining the value to use can be difficult. For instance, if the following line is in your program, the results probably are not going to be what you expected:
#define INT_MAX 0x8000 /* Really not a good idea! */
In this example, you expect INT_MAX to contain the value (–32768); the compiler promotes the constant to unsigned, however, and the value of INT_MAX, 32,768, is probably not what you expect.
A much easier solution exists. A number of useful identifiers are defined in the limits.h header file in ANSI C (see Table 2.3). Use limits.h so that predefined identifiers can define the limits for the integer data types. The values shown in Tables 2.3 through 2.5 represent the ANSI limits, although many compilers exceed the values shown.
Table 2.3. C’s int limits identifiers, from limits.h.
Identifier |
Value |
Description |
|
char types |
|
CHAR_BIT |
8 |
Number of bits in a char type |
SCHAR_MIN |
–127 |
Minimum signed char type |
SCHAR_MAX |
127 |
Maximum signed char type |
UCHAR_MAX |
255 |
Maximum unsigned char type |
CHAR_MIN |
SCHAR_MIN |
Minimum char value, if characters |
|
|
are unsigned |
CHAR_MAX |
SCHAR_MAX |
Maximum char value, if characters |
|
|
are unsigned |
CHAR_MIN |
0 |
If characters are signed |
continues
21

Part I • Honing Your C Skills
Table 2.3. continued
Identifier |
Value |
Description |
CHAR_MAX |
UCHAR_MAX |
If characters are signed |
MB_LEN_MAX |
1 |
Maximum number of bytes in |
|
|
multibyte char |
|
short int types |
|
SHRT_MIN |
–32767 |
Minimum (signed) short type |
SHRT_MAX |
32767 |
Maximum (signed) short type |
USHRT_MAX |
65535 |
Maximum unsigned short type |
INT_MIN |
–32767 |
Minimum (signed) int type |
INT_MAX |
32767 |
Maximum (signed) int type |
UINT_MAX |
65535 |
Maximum unsigned int type |
|
long int types |
|
LONG_MIN |
–2147483647 |
Minimum (signed) long type |
LONG_MAX |
2147483647 |
Maximum (signed) long type |
ULONG_MAX |
4294967295 |
Maximum unsigned long type |
|
|
|
Three different-size variables can be defined for floating-point variables (see Table 2.4). The identifiers for floating-point numbers are subdivided into three parts. The first three letters indicate the size of the floating-point object: DBL_ for a double, FLT_ for a float, and LDBL_ for a long double.
Table 2.4. C’s floating-point limits identifiers, from float.h.
Identifier |
Value |
Description |
DBL_DIG |
15 |
Number of |
|
|
decimal digits of |
|
|
precision |
22

|
|
Data Types, Constants, Variables, and Arrays |
C C C |
||
|
|
|
|
C2C |
|
|
|
|
|
C C C |
|
|
|
|
|
C |
|
|
|
|
|
|
|
|
Identifier |
Value |
Description |
|
|
|
|
|
|
|
|
|
DBL_EPSILON |
2.2204460492503131e-016 |
Smallest value |
|
|
|
|
|
that, added to |
|
|
|
|
|
1.0, makes the |
||
|
|
|
result no longer |
||
|
|
|
equal to 1.0 |
|
|
|
DBL_MANT_DIG |
53 |
Number of bits in |
||
|
|
|
mantissa |
|
|
|
DBL_MAX |
1.7976931348623158e+308 |
Maximum value |
||
|
DBL_MAX_10_EXP |
308 |
Maximum |
|
|
|
|
|
decimal exponent |
||
|
DBL_MAX_EXP |
1024 |
Maximum binary |
||
|
|
|
exponent |
|
|
|
DBL_MIN |
2.2250738585072014e-308 |
Minimum |
|
|
|
|
|
positive value |
|
|
|
DBL_MIN_10_EXP |
(-307) |
Minimum |
|
|
|
|
|
decimal exponent |
||
|
DBL_MIN_EXP |
(-1021) |
Minimum binary |
||
|
|
|
exponent |
|
|
|
DBL_RADIX |
2 |
Exponent radix |
||
|
DBL_ROUNDS |
1 |
Addition round- |
||
|
|
|
ing: near |
|
|
|
FLT_DIG |
7 |
Number of |
|
|
|
|
|
decimal digits of |
||
|
|
|
precision |
|
|
|
FLT_EPSILON |
1.192092896e-07F |
Smallest value |
|
|
|
|
|
that, added to |
|
|
|
|
|
1.0, makes the |
||
|
|
|
result no longer |
||
|
|
|
equal to 1.0 |
|
|
continues
23

Part I • Honing Your C Skills
Table 2.4. continued
Identifier |
Value |
Description |
FLT_MANT_DIG |
24 |
Number of bits in |
|
|
mantissa |
FLT_MAX |
3.402823466e+38F |
Maximum value |
FLT_MAX_10_EXP |
38 |
Maximum |
|
|
decimal exponent |
FLT_MAX_EXP |
128 |
Maximum binary |
|
|
exponent |
FLT_MIN |
1.175494351e-38F |
Minimum |
|
|
positive value |
FLT_MIN_10_EXP |
(-37) |
Minimum |
|
|
decimal exponent |
FLT_MIN_EXP |
(-125) |
Minimum binary |
|
|
exponent |
FLT_RADIX |
2 |
Exponent radix |
FLT_ROUNDS |
1 |
Addition round- |
|
|
ing: near |
LDBL_DIG |
19 |
Number of |
|
|
decimal digits of |
|
|
precision |
LDBL_EPSILON |
5.4210108624275221706e-020 |
Smallest value |
|
|
that, added to |
|
|
1.0, makes the |
|
|
result no longer |
|
|
equal to 1.0 |
LDBL_MANT_DIG |
64 |
Number of bits in |
|
|
mantissa |
LDBL_MAX |
1.189731495357231765e+4932L |
Maximum value |
24

|
|
Data Types, Constants, Variables, and Arrays |
C C C |
||
|
|
|
|
C2C |
|
|
|
|
|
C C C |
|
|
|
|
|
C |
|
|
|
|
|
|
|
|
Identifier |
Value |
Description |
|
|
|
|
|
|
|
|
|
LDBL_MAX_10_EXP 4932 |
Maximum |
|
|
|
|
|
|
decimal exponent |
||
|
LDBL_MAX_EXP |
16384 |
Maximum binary |
||
|
|
|
exponent |
|
|
|
LDBL_MIN |
3.3621031431120935063e-4932L |
Minimum |
|
|
|
|
|
positive value |
|
|
|
LDBL_MIN_10_EXP (-4931) |
Minimum |
|
|
|
|
|
|
decimal exponent |
||
|
LDBL_MIN_EXP |
(-16381) |
Minimum binary |
||
|
|
|
exponent |
|
|
|
LDBL_RADIX |
2 |
Exponent radix |
||
|
LDBL_ROUNDS |
1 |
Addition |
|
|
|
|
|
rounding: near |
||
|
|
|
|
|
|
Other identifiers generally are defined in float.h; however, they usually are either CPUor compiler-dependent. Refer to your compiler manual for a description of these other identifiers, or print float.h to see whether comments in the file help you understand the purpose of the identifiers.
Rather than code constants for these values into your program, you should use one of the predefined identifiers shown in Tables 2.3 and 2.4. These identifiers allow for better portability and make the meaning of your program clear.
Constants
All homes are buildings, but not all buildings are homes. All literals are constants, but not all constants are literals. Maybe this example is not clear, but with the const modifier applied to a variable, it becomes nonmodifiable—a constant. Let’s look at a few constants. Constants can come in any data type that the C compiler supports. A special constant, the string, can be used to either initialize a character array or be substituted for one. Table 2.5 shows a number of constants.
25

Part I • Honing Your C Skills
Table 2.5. Constants in C.
Constant |
Description |
Comments |
123 |
int, in the smallest |
|
size and type that |
|
will hold the value |
|
specified |
123U |
unsigned int, in the |
|
smallest size and |
|
type that will hold |
|
the value specified |
123L |
long int, signed |
123UL |
long int, unsigned |
‘A’ |
Character constant |
“ABCDE” |
Character string |
|
constant |
Never a decimal point; a unary is allowed if the value is negative. Be careful not to specify a value
too large for the data type for which it is being used. The C compiler may change the size (or to an unsigned integer) if necessary to fit the value into the specified data type.
Never a decimal point; a unary is not allowed because the value must be positive. Be careful not to specify a value too large for
the data type for which it is being used. The C compiler may change the size if necessary to fit the value into the specified data type.
Never a decimal point; a unary is allowed if the value is negative.
Never a decimal point; a unary is not allowed because the value must be positive.
A single character, enclosed within single quotes. For nonprintable characters, you can use \xNN, where NN are valid hex digits.
One or more characters (to the limit of 509) enclosed in double quotes. For nonprintable characters, you can use \xNN, where NN are valid hex digits.
26

|
|
Data Types, Constants, Variables, and Arrays |
C C C |
|
|
|
|
C2C |
|
|
|
|
C C C |
|
|
|
|
C |
|
|
|
|
|
|
|
Constant Description |
Comments |
|
|
|
|
|
|
|
1.23double—floating- Always a decimal point; both leading
|
point constant |
and trailing zeros are optional, but for |
|
|
readability, at least one digit should |
|
|
precede and follow the decimal point. |
1.23F |
float—floating- |
Always a decimal point; both leading |
|
point constant |
and trailing zeros are optional, but for |
|
|
readability, at least one digit should |
|
|
precede and follow the decimal point. |
1.23L |
long double— |
Always a decimal point; both leading |
|
floating-point |
and trailing zeros are optional, but for |
|
constant |
readability, at least one digit should |
|
|
precede and follow the decimal point. |
|
|
|
The suffixes shown in Table 2.5 can be in either upperor lowercase. I prefer uppercase because a lowercase l is difficult to distinguish from the number 1. If a number that does not fit in the default size is presented to the compiler, it either is changed to an unsigned type or its size is increased. As an example, when the value 45000 is encountered, the compiler assumes that is an unsigned value; 500000, which is too large for either a signed or unsigned 16-bit value, is promoted to a 32-bit long value.
String constants present several unique situations. First, unlike numeric constants, it’s possible to obtain the address of a string constant. This capability is necessary because string functions use addresses (see Listing 2.1).
Listing 2.1. BADSTR.C.
/* BADSTR, written 12 May 1992 by Peter D. Hipson */ /* An example of changing a string constant. */
#include <stdio.h> // Make includes first part of file #include <string.h>
int main(void); // Declare main() and the fact that this program doesn’t // use any passed parameters.
continues
27

Part I • Honing Your C Skills
Listing 2.1. continued
int main()
{
char szMyName[] = “John Q. Public”; char szYourName[50];
szYourName[0] = ‘\0’;
strcpy(szYourName, szMyName); // szYourName is now the same as // szMyName.
printf(“MyName ‘%s’ YourName ‘%s’ \n”, szMyName,
szYourName);
strcpy(szMyName, “My New Name”); // strcpy() actually receives the // address of the constant
// “My New Name”
printf(“MyName ‘%s’ YourName ‘%s’ \n”, szMyName,
szYourName);
printf(“Before: MyName ‘%s’ Constant ‘%s’ \n”, szMyName,
“My New Name”);
strcpy(“My New Name”, // strcpy() actually receives the address szYourName); // of the constant “My New Name”
// This will fail and destroy the constant!
printf(“After: MyName ‘%s’ Constant ‘%s’ \n”, szMyName,
“My New Name”);
28