The exponent in a hexadecimal floating constant is a possibly-signed decimal integer that specifies a power of 2 (not 10 or 16) to multiply into the number.
Here are some examples:
0xAp2 // 40 in decimal 0xAp-1 // 5 in decimal 0x2.0Bp4 // 16.75 decimal 0xE.2p3 // 121 decimal 0x123.ABCp0 //<PHONE_NUMBER>375 in decimal 0x123.ABCp4 // 4666.734375 in decimal 0x100p-8 // 1 0x10p-4 // 1 0x1p+4 // 16 0x1p+8 // 256
See Floating-Point Data Types.
Next: Invalid Numbers, Previous: Floating Constants, Up: Constants [Contents][Index]
A complex number consists of a real part plus an imaginary part. (Either or both parts may be zero.) This section explains how to write numeric constants with imaginary values. By adding these to ordinary real-valued numeric constants, we can make constants with complex values.
The simple way to write an imaginary-number constant is to attach the
suffix ‘i’ or ‘I’, or ‘j’ or ‘J’, to an integer or
floating-point constant. For example, 2.5fi
has type
_Complex float
and 3i
has type _Complex int
.
The four alternative suffix letters are all equivalent.
The other way to write an imaginary constant is to multiply a real
constant by _Complex_I
, which represents the imaginary number
i. Standard C doesn’t support suffixing with ‘i’ or ‘j’, so
this clunky way is needed.
To write a complex constant with a nonzero real part and a nonzero imaginary part, write the two separately and add them, like this:
4.0 + 3.0i
That gives the value 4 + 3i, with type _Complex double
.
Such a sum can include multiple real constants, or none. Likewise, it can include multiple imaginary constants, or none. For example:
_Complex double foo, bar, quux; foo = 2.0i + 4.0 + 3.0i; /* Imaginary part is 5.0. */ bar = 4.0 + 12.0; /* Imaginary part is 0.0. */ quux = 3.0i + 15.0i; /* Real part is 0.0. */
See Complex Data Types.
Next: Character Constants, Previous: Imaginary Constants, Up: Constants [Contents][Index]
Some number-like constructs which are not really valid as numeric constants are treated as numbers in preprocessing directives. If these constructs appear outside of preprocessing, they are erroneous. See Preprocessing Tokens.
Sometimes we need to insert spaces to separate tokens so that they
won’t be combined into a single number-like construct. For example,
0xE+12
is a preprocessing number that is not a valid numeric
constant, so it is a syntax error. If what we want is the three
tokens 0xE + 12
, we have to use those spaces as separators.
Next: String Constants, Previous: Invalid Numbers, Up: Constants [Contents][Index]
A character constant is written with single quotes, as in
'c'
. In the simplest case, c is a single ASCII
character that the constant should represent. The constant has type
int
, and its value is the character code of that character.
For instance, 'a'
represents the character code for the letter
‘a’: 97, that is.
To put the ‘'’ character (single quote) in the character
constant, quote it with a backslash (‘\’). This character
constant looks like '\''
. This sort of sequence, starting with
‘\’, is called an escape sequence—the backslash character
here functions as a kind of escape character.
To put the ‘\’ character (backslash) in the character constant,
quote it likewise with ‘\’ (another backslash). This character
constant looks like '\\'
.
Here are all the escape sequences that represent specific characters in a character constant. The numeric values shown are the corresponding ASCII character codes, as decimal numbers.
'\a' ⇒ 7 /* alarm, CTRL-g */ '\b' ⇒ 8 /* backspace, BS, CTRL-h */ '\t' ⇒ 9 /* tab, TAB, CTRL-i */ '\n' ⇒ 10 /* newline, CTRL-j */ '\v' ⇒ 11 /* vertical tab, CTRL-k */ '\f' ⇒ 12 /* formfeed, CTRL-l */ '\r' ⇒ 13 /* carriage return, RET, CTRL-m */ '\e' ⇒ 27 /* escape character, ESC, CTRL-[ */ '\\' ⇒ 92 /* backslash character, \ */ '\'' ⇒ 39 /* singlequote character, ' */ '\"' ⇒ 34 /* doublequote character, " */ '\?' ⇒ 63 /* question mark, ? */
‘\e’ is a GNU C extension; to stick to standard C, write ‘\33’.
You can also write octal and hex character codes as ‘\octalcode’ or ‘\xhexcode’. Decimal is not an option here, so octal codes do not need to start with ‘0’.
The character constant’s value has type int
. However, the
character code is treated initially as a char
value, which is
then converted to int
. If the character code is greater than
127 (0177
in octal), the resulting int
may be negative
on a platform where the type char
is 8 bits long and signed.
Next: UTF-8 String Constants, Previous: Character Constants, Up: Constants [Contents][Index]
A string constant represents a series of characters. It starts with ‘"’ and ends with ‘"’; in between are the contents of the string. Quoting special characters such as ‘"’, ‘\’ and newline in the contents works in string constants as in character constants. In a string constant, ‘'’ does not need to be quoted.
A string constant defines an array of characters which contains the specified characters followed by the null character (code 0). Using the string constant is equivalent to using the name of an array with those contents. In simple cases, the length in bytes of the string constant is one greater than the number of characters written in it.
As with any array in C, using the string constant in an expression
converts the array to a pointer (see Pointers) to the array’s
first element (see Accessing Array Elements). This pointer will
have type char *
because it points to an element of type
char
. char *
is an example of a type designator for a
pointer type (see Pointer Type Designators). That type is used
for strings generally, not just the strings expressed as constants
in a program.
Thus, the string constant "Foo!"
is almost
equivalent to declaring an array like this
char string_array_1[] = {'F', 'o', 'o', '!', '\0' };
and then using string_array_1
in the program. There
are two differences, however:
Newlines are not allowed in the text of a string constant. The motive for this prohibition is to catch the error of omitting the closing ‘"’. To put a newline in a constant string, write it as ‘\n’ in the string constant.
A real null character in the source code inside a string constant causes a warning. To put a null character in the middle of a string constant, write ‘\0’ or ‘\000’.
Consecutive string constants are effectively concatenated. Thus,
"Fo" "o!" is equivalent to "Foo!"
This is useful for writing a string containing multiple lines, like this:
"This message is so long that it needs more than\n" "a single line of text. C does not allow a newline\n" "to represent itself in a string constant, so we have to\n" "write \\n to put it in the string. For readability of\n" "the source code, it is advisable to put line breaks in\n" "the source where they occur in the contents of the\n" "constant.\n"
The sequence of a backslash and a newline is ignored anywhere in a C program, and that includes inside a string constant. Thus, you can write multi-line string constants this way:
"This is another way to put newlines in a string constant\n\ and break the line after them in the source code."
However, concatenation is the recommended way to do this.
You can also write perverse string constants like this,
"Fo\ o!"
but don’t do that—write it like this instead:
"Foo!"
Be careful to avoid passing a string constant to a function that
modifies the string it receives. The memory where the string constant
is stored may be read-only, which would cause a fatal SIGSEGV
signal that normally terminates the function (see Signals. Even
worse, the memory may not be read-only. Then the function might
modify the string constant, thus spoiling the contents of other string
constants that are supposed to contain the same value and are unified
by the compiler.
Next: Unicode Character Codes, Previous: String Constants, Up: Constants [Contents][Index]
Writing ‘u8’ immediately before a string constant, with no intervening space, means to represent that string in UTF-8 encoding as a sequence of bytes. UTF-8 represents ASCII characters with a single byte, and represents non-ASCII Unicode characters (codes 128 and up) as multibyte sequences. Here is an example of a UTF-8 constant:
u8"A cónstàñt"
This constant occupies 13 bytes plus the terminating null, because each of the accented letters is a two-byte sequence.
Concatenating an ordinary string with a UTF-8 string conceptually produces another UTF-8 string. However, if the ordinary string contains character codes 128 and up, the results cannot be relied on.
Next: Wide Character Constants, Previous: UTF-8 String Constants, Up: Constants [Contents][Index]
You can specify Unicode characters, for individual character constants or as part of string constants (see String Constants), using escape sequences. Use the ‘\u’ escape sequence with a 16-bit hexadecimal Unicode character code. If the code value is too big for 16 bits, use the ‘\U’ escape sequence with a 32-bit hexadecimal Unicode character code. (These codes are called universal character names.) For example,
\u6C34 /* 16-bit code (UTF-16) */ \U0010ABCD /* 32-bit code (UTF-32) */
One way to use these is in UTF-8 string constants (see UTF-8 String Constants). For instance,
u8"fóó \u6C34 \U0010ABCD"
You can also use them in wide character constants (see Wide Character Constants), like this:
u'\u6C34' /* 16-bit code */ U'\U0010ABCD' /* 32-bit code */
and in wide string constants (see Wide String Constants), like this:
u"\u6C34\u6C33" /* 16-bit code */ U"\U0010ABCD" /* 32-bit code */
Codes in the range of D800
through DFFF
are not valid
in Unicode. Codes less than 00A0
are also forbidden, except for
0024
, 0040
, and 0060
; these characters are
actually ASCII control characters, and you can specify them with other
escape sequences (see Character Constants).
Next: Wide String Constants, Previous: Unicode Character Codes, Up: Constants [Contents][Index]
A wide character constant represents characters with more than 8 bits of character code. This is an obscure feature that we need to document but that you probably won’t ever use. If you’re just learning C, you may as well skip this section.
The original C wide character constant looks like ‘L’ (upper
case!) followed immediately by an ordinary character constant (with no
intervening space). Its data type is wchar_t
, which is an
alias defined in stddef.h for one of the standard integer
types. Depending on the platform, it could be 16 bits or 32 bits. If
it is 16 bits, these character constants use the UTF-16 form of
Unicode; if 32 bits, UTF-32.
There are also Unicode wide character constants which explicitly
specify the width. These constants start with ‘u’ or ‘U’
instead of ‘L’. ‘u’ specifies a 16-bit Unicode wide
character constant, and ‘U’ a 32-bit Unicode wide character
constant. Their types are, respectively, char16_t
and
char32_t
; they are declared in the header file
uchar.h. These character constants are valid even if
uchar.h is not included, but some uses of them may be
inconvenient without including it to declare those type names.
The character represented in a wide character constant can be an
ordinary ASCII character. L'a'
, u'a'
and U'a'
are all valid, and they are all equal to 'a'
.
In all three kinds of wide character constants, you can write a non-ASCII Unicode character in the constant itself; the constant’s value is the character’s Unicode character code. Or you can specify the Unicode character with an escape sequence (see Unicode Character Codes).
Previous: Wide Character Constants, Up: Constants [Contents][Index]
A wide string constant stands for an array of 16-bit or 32-bit characters. They are rarely used; if you’re just learning C, you may as well skip this section.
There are three kinds of wide string constants, which differ in the data type used for each character in the string. Each wide string constant is equivalent to an array of integers, but the data type of those integers depends on the kind of wide string. Using the constant in an expression will convert the array to a pointer to its first element, as usual for arrays in C (see Accessing Array Elements). For each kind of wide string constant, we state here what type that pointer will be.
char16_t
This is a 16-bit Unicode wide string constant: each element is a
16-bit Unicode character code with type char16_t
, so the string
has the pointer type char16_t *
. (That is a type designator;
see Pointer Type Designators.) The constant is written as
‘u’ (which must be lower case) followed (with no intervening
space) by a string constant with the usual syntax.
char32_t
This is a 32-bit Unicode wide string constant: each element is a
32-bit Unicode character code, and the string has type char32_t *
.
It’s written as ‘U’ (which must be upper case) followed (with no
intervening space) by a string constant with the usual syntax.
wchar_t
This is the original kind of wide string constant. It’s written as
‘L’ (which must be upper case) followed (with no intervening
space) by a string constant with the usual syntax, and the string has
type wchar_t *
.
The width of the data type wchar_t
depends on the target
platform, which makes this kind of wide string somewhat less useful
than the newer kinds.
char16_t
and char32_t
are declared in the header file
uchar.h. wchar_t
is declared in stddef.h.
Consecutive wide string constants of the same kind concatenate, just like ordinary string constants. A wide string constant concatenated with an ordinary string constant results in a wide string constant. You can’t concatenate two wide string constants of different kinds. You also can’t concatenate a wide string constant (of any kind) with a UTF-8 string constant.
Each data type has a size, which is the number of bytes
(see Storage) that it occupies in memory. To refer to the size in
a C program, use sizeof
. There are two ways to use it:
sizeof expression
This gives the size of expression, based on its data type. It
does not calculate the value of expression, only its size, so if
expression includes side effects or function calls, they do not
happen. Therefore, sizeof
is always a compile-time operation
that has zero run-time cost.
A value that is a bit field (see Bit Fields) is not allowed as an
operand of sizeof
.
For example,
double a; i = sizeof a + 10;
sets i
to 18 on most computers because a
occupies 8 bytes.
Here’s how to determine the number of elements in an array
array
:
(sizeof array / sizeof array[0])
The expression sizeof array
gives the size of the array, not
the size of a pointer to an element. However, if expression is
a function parameter that was declared as an array, that
variable really has a pointer type (see Array Parm Pointer), so
the result is the size of that pointer.
sizeof (type)
This gives the size of type. For example,
i = sizeof (double) + 10;
is equivalent to the previous example.
You can’t apply sizeof
to an incomplete type (see Incomplete Types), nor void
. Using it on a function type gives 1 in GNU
C, which makes adding an integer to a function pointer work as desired
(see Pointer Arithmetic).
Warning: When you use sizeof
with a type
instead of an expression, you must write parentheses around the type.
Warning: When applying sizeof
to the result of a cast
(see Explicit Type Conversion), you must write parentheses around
the cast expression to avoid an ambiguity in the grammar of C.
Specifically,
sizeof (int) -x
parses as
(sizeof (int)) - x
If what you want is
sizeof ((int) -x)
you must write it that way, with parentheses.
The data type of the value of the sizeof
operator is always one
of the unsigned integer types; which one of those types depends on the
machine. The header file stddef.h
defines the typedef name
size_t
as an alias for this type. See Defining Typedef Names.
Next: Structures, Previous: Type Size, Up: Top [Contents][Index]
Among high-level languages, C is rather low level, close to the machine. This is mainly because it has explicit pointers. A pointer value is the numeric address of data in memory. The type of data to be found at that address is specified by the data type of the pointer itself. The unary operator ‘*’ gets the data that a pointer points to—this is called dereferencing the pointer.
C also allows pointers to functions, but since there are some differences in how they work, we treat them later. See Function Pointers.
| • Address of Data | Using the “address-of” operator. | |
| • Pointer Types | For each type, there is a pointer type. | |
| • Pointer Declarations | Declaring variables with pointer types. | |
| • Pointer Type Designators | Designators for pointer types. | |
| • Pointer Dereference | Accessing what a pointer points at. | |
| • Null Pointers | Pointers which do not point to any object. | |
| • Invalid Dereference | Dereferencing null or invalid pointers. | |
| • Void Pointers | Totally generic pointers, can cast to any. | |
| • Pointer Comparison | Comparing memory address values. | |
| • Pointer Arithmetic | Computing memory address values. | |
| • Pointers and Arrays | Using pointer syntax instead of array syntax. | |
| • Pointer Arithmetic Low Level | More about computing memory address values. | |
| • Pointer Increment/Decrement | Incrementing and decrementing pointers. | |
| • Pointer Arithmetic Drawbacks | A common pointer bug to watch out for. | |
| • Pointer-Integer Conversion | Converting pointer types to integer types. | |
| • Printing Pointers | Using printf for a pointer’s value.
|
Next: Pointer Types, Up: Pointers [Contents][Index]
The most basic way to make a pointer is with the “address-of” operator, ‘&’. Let’s suppose we have these variables available:
int i; double a[5];
Now, &i
gives the address of the variable i
—a pointer
value that points to i
’s location—and &a[3]
gives the
address of the element 3 of a
. (It is actually the fourth
element in the array, since the first element has index 0.)
The address-of operator is unusual because it operates on a place to store a value (an lvalue, see Lvalues), not on the value currently stored there. (The left argument of a simple assignment is unusual in the same way.) You can use it on any lvalue except a bit field (see Bit Fields) or a constructor (see Structure Constructors).
Next: Pointer Declarations, Previous: Address of Data, Up: Pointers [Contents][Index]
For each data type t, there is a type for pointers to type t. For these variables,
int i; double a[5];
i
has type int
; we say
&i
is a “pointer to int
.”
a
has type double[5]
; we say &a
is a “pointer to
arrays of five double
s.”
a[3]
has type double
; we say &a[3]
is a “pointer
to double
.”
Next: Pointer Type Designators, Previous: Pointer Types, Up: Pointers [Contents][Index]
The way to declare that a variable foo
points to type t is
t *foo;
To remember this syntax, think “if you dereference foo
, using
the ‘*’ operator, what you get is type t. Thus, foo
points to type t.”
Thus, we can declare variables that hold pointers to these three types, like this:
int *ptri; /* Pointer toint
. */ double *ptrd; /* Pointer todouble
. */ double (*ptrda)[5]; /* Pointer todouble[5]
. */
‘int *ptri;’ means, “if you dereference ptri
, you get an
int
.” ‘double (*ptrda)[5];’ means, “if you dereference
ptrda
, then subscript it by an integer less than 5, you get a
double
.” The parentheses express the point that you would
dereference it first, then subscript it.
Contrast the last one with this:
double *aptrd[5]; /* Array of five pointers to double
. */
Because ‘*’ has higher syntactic precedence than subscripting,
you would subscript aptrd
then dereference it. Therefore, it
declares an array of pointers, not a pointer.
Next: Pointer Dereference, Previous: Pointer Declarations, Up: Pointers [Contents][Index]
Every type in C has a designator; you make it by deleting the variable name and the semicolon from a declaration (see Type Designators). Here are the designators for the pointer types of the example declarations in the previous section:
int * /* Pointer toint
. */ double * /* Pointer todouble
. */ double (*)[5] /* Pointer todouble[5]
. */
Remember, to understand what type a designator stands for, imagine the
variable name that would be in the declaration, and figure out what
type it would declare that variable with. double (*)[5]
can
only come from double (*variable)[5]
, so it’s a pointer
which, when dereferenced, gives an array of 5 double
s.
Next: Null Pointers, Previous: Pointer Type Designators, Up: Pointers [Contents][Index]
The main use of a pointer value is to dereference it (access the
data it points at) with the unary ‘*’ operator. For instance,
*&i
is the value at i
’s address—which is just
i
. The two expressions are equivalent, provided &i
is
valid.
A pointer-dereference expression whose type is data (not a function) is an lvalue.
Pointers become really useful when we store them somewhere and use them later. Here’s a simple example to illustrate the practice:
{
int i;
int *ptr;
ptr = &i;
i = 5;
…
return *ptr; /* Returns 5, fetched from i
. */
}
This shows how to declare the variable ptr
as type
int *
(pointer to int
), store a pointer value into it
(pointing at i
), and use it later to get the value of the
object it points at (the value in i
).
If anyone can provide a useful example which is this basic, I would be grateful.
Next: Invalid Dereference, Previous: Pointer Dereference, Up: Pointers [Contents][Index]
A pointer value can be null, which means it does not point to
any object. The cleanest way to get a null pointer is by writing
NULL
, a standard macro defined in stddef.h. You can
also do it by casting 0 to the desired pointer type, as in
(char *) 0
. (The cast operator performs explicit type conversion;
See Explicit Type Conversion.)
You can store a null pointer in any lvalue whose data type is a pointer type:
char *foo; foo = NULL;
These two, if consecutive, can be combined into a declaration with initializer,
char *foo = NULL;
You can also explicitly cast NULL
to the specific pointer type
you want—it makes no difference.
char *foo; foo = (char *) NULL;
To test whether a pointer is null, compare it with zero or
NULL
, as shown here:
if (p != NULL)
/* p
is not null. */
operate (p);
Since testing a pointer for not being null is basic and frequent, all
but beginners in C will understand the conditional without need for
!= NULL
:
if (p)
/* p
is not null. */
operate (p);
Next: Void Pointers, Previous: Null Pointers, Up: Pointers [Contents][Index]
Trying to dereference a null pointer is an error. On most platforms,
it generally causes a signal, usually SIGSEGV
(see Signals).
char *foo = NULL;
c = *foo; /* This causes a signal and terminates. */
Likewise a pointer that has the wrong alignment for the target data type (on most types of computer), or points to a part of memory that has not been allocated in the process’s address space.
The signal terminates the program, unless the program has arranged to handle the signal (see The GNU C Library in The GNU C Library Reference Manual).
However, the signal might not happen if the dereference is optimized
away. In the example above, if you don’t subsequently use the value
of c
, GCC might optimize away the code for *foo
. You
can prevent such optimization using the volatile
qualifier, as
shown here:
volatile char *p; volatile char c; c = *p;
You can use this to test whether p
points to unallocated
memory. Set up a signal handler first, so the signal won’t terminate
the program.
Next: Pointer Comparison, Previous: Invalid Dereference, Up: Pointers [Contents][Index]
The peculiar type void *
, a pointer whose target type is
void
, is used often in C. It represents a pointer to
we-don’t-say-what. Thus,
void *numbered_slot_pointer (int);
declares a function numbered_slot_pointer
that takes an
integer parameter and returns a pointer, but we don’t say what type of
data it points to.
With type void *
, you can pass the pointer around and test
whether it is null. However, dereferencing it gives a void
value that can’t be used (see The Void Type). To dereference the
pointer, first convert it to some other pointer type.
Assignments convert void *
automatically to any other pointer
type, if the left operand has a pointer type; for instance,
{
int *p;
/* Converts return value to int *
. */
p = numbered_slot_pointer (5);
…
}
Passing an argument of type void *
for a parameter that has a
pointer type also converts. For example, supposing the function
hack
is declared to require type float *
for its
argument, this will convert the null pointer to that type.
/* Declarehack
that way. We assume it is defined somewhere else. */ void hack (float *); … /* Now callhack
. */ { /* Converts return value ofnumbered_slot_pointer
tofloat *
to pass it tohack
. */ hack (numbered_slot_pointer (5)); … }
You can also convert to another pointer type with an explicit cast (see Explicit Type Conversion), like this:
(int *) numbered_slot_pointer (5)
Here is an example which decides at run time which pointer type to convert to:
void extract_int_or_double (void *ptr, bool its_an_int) { if (its_an_int) handle_an_int (*(int *)ptr); else handle_a_double (*(double *)ptr); }
The expression *(int *)ptr
means to convert ptr
to type int *
, then dereference it.
Next: Pointer Arithmetic, Previous: Void Pointers, Up: Pointers [Contents][Index]
Two pointer values are equal if they point to the same location, or if
they are both null. You can test for this with ==
and
!=
. Here’s a trivial example:
{ int i; int *p, *q; p = &i; q = &i; if (p == q) printf ("This will be printed.\n"); if (p != q) printf ("This won't be printed.\n"); }
Ordering comparisons such as >
and >=
operate on
pointers by converting them to unsigned integers. The C standard says
the two pointers must point within the same object in memory, but on
GNU/Linux systems these operations simply compare the numeric values
of the pointers.
The pointer values to be compared should in principle have the same type, but they are allowed to differ in limited cases. First of all, if the two pointers’ target types are nearly compatible (see Compatible Types), the comparison is allowed.
If one of the operands is void *
(see Void Pointers) and
the other is another pointer type, the comparison operator converts
the void *
pointer to the other type so as to compare them.
(In standard C, this is not allowed if the other type is a function
pointer type, but that works in GNU C.)
Comparison operators also allow comparing the integer 0 with a pointer value. Thus works by converting 0 to a null pointer of the same type as the other operand.
Next: Pointers and Arrays, Previous: Pointer Comparison, Up: Pointers [Contents][Index]
Adding an integer (positive or negative) to a pointer is valid in C. It assumes that the pointer points to an element in an array, and advances or retracts the pointer across as many array elements as the integer specifies. Here is an example, in which adding a positive integer advances the pointer to a later element in the same array.
void incrementing_pointers () { int array[5] = { 45, 29, 104, -3, 123456 }; int elt0, elt1, elt4; int *p = &array[0]; /* Nowp
points at element 0. Fetch it. */ elt0 = *p; ++p; /* Nowp
points at element 1. Fetch it. */ elt1 = *p; p += 3; /* Nowp
points at element 4 (the last). Fetch it. */ elt4 = *p; printf ("elt0 %d elt1 %d elt4 %d.\n", elt0, elt1, elt4); /* Prints elt0 45 elt1 29 elt4 123456. */ }
Here’s an example where adding a negative integer retracts the pointer to an earlier element in the same array.
void decrementing_pointers () { int array[5] = { 45, 29, 104, -3, 123456 }; int elt0, elt3, elt4; int *p = &array[4]; /* Nowp
points at element 4 (the last). Fetch it. */ elt4 = *p; --p; /* Nowp
points at element 3. Fetch it. */ elt3 = *p; p -= 3; /* Nowp
points at element 0. Fetch it. */ elt0 = *p; printf ("elt0 %d elt3 %d elt4 %d.\n", elt0, elt3, elt4); /* Prints elt0 45 elt3 -3 elt4 123456. */ }
If one pointer value was made by adding an integer to another pointer value, it should be possible to subtract the pointer values and recover that integer. That works too in C.
void subtract_pointers () { int array[5] = { 45, 29, 104, -3, 123456 }; int *p0, *p3, *p4; int *p = &array[4]; /* Nowp
points at element 4 (the last). Save the value. */ p4 = p; --p; /* Nowp
points at element 3. Save the value. */ p3 = p; p -= 3; /* Nowp
points at element 0. Save the value. */ p0 = p; printf ("%d, %d, %d, %d\n", p4 - p0, p0 - p0, p3 - p0, p0 - p3); /* Prints 4, 0, 3, -3. */ }
The addition operation does not know where arrays are. All it does is add the integer (multiplied by object size) to the value of the pointer. When the initial pointer and the result point into a single array, the result is well-defined.
Warning: Only experts should do pointer arithmetic involving pointers into different memory objects.
The difference between two pointers has type int
, or
long
if necessary (see Integer Types). The clean way to
declare it is to use the typedef name ptrdiff_t
defined in the
file stddef.h.
This definition of pointer subtraction is consistent with
pointer-integer addition, in that (p3 - p1) + p1
equals
p3
, as in ordinary algebra.
In standard C, addition and subtraction are not allowed on void
*
, since the target type’s size is not defined in that case.
Likewise, they are not allowed on pointers to function types.
However, these operations work in GNU C, and the “size of the target
type” is taken as 1.
Next: Pointer Arithmetic Low Level, Previous: Pointer Arithmetic, Up: Pointers [Contents][Index]
The clean way to refer to an array element is
array[index]
. Another, complicated way to do the
same job is to get the address of that element as a pointer, then
dereference it: * (&array[0] + index)
(or
equivalently * (array + index)
). This first gets a
pointer to element zero, then increments it with +
to point to
the desired element, then gets the value from there.
That pointer-arithmetic construct is the definition of square
brackets in C. a[b]
means, by definition,
*(a + b)
. This definition uses a and b
symmetrically, so one must be a pointer and the other an integer; it
does not matter which comes first.
Since indexing with square brackets is defined in terms of addition
and dereference, that too is symmetrical. Thus, you can write
3[array]
and it is equivalent to array[3]
. However, it
would be foolish to write 3[array]
, since it has no advantage
and could confuse people who read the code.
It may seem like a discrepancy that the definition *(a +
b)
requires a pointer, but array[3]
uses an array value
instead. Why is this valid? The name of the array, when used by
itself as an expression (other than in sizeof
), stands for a
pointer to the arrays’s zeroth element. Thus, array + 3
converts array
implicitly to &array[0]
, and the result
is a pointer to element 3, equivalent to &array[3]
.
Since square brackets are defined in terms of such addition,
array[3]
first converts array
to a pointer. That’s why
it works to use an array directly in that construct.
Next: Pointer Increment/Decrement, Previous: Pointers and Arrays, Up: Pointers [Contents][Index]
The behavior of pointer arithmetic is theoretically defined only when the pointer values all point within one object allocated in memory. But the addition and subtraction operators can’t tell whether the pointer values are all within one object. They don’t know where objects start and end. So what do they really do?
Adding pointer p to integer i treats p as a memory
address, which is in fact an integer—call it pint. It treats
i as a number of elements of the type that p points to.
These elements’ sizes add up to i * sizeof (*p)
.
So the sum, as an integer, is pint + i * sizeof
(*p)
. This value is reinterpreted as a pointer like p.
If the starting pointer value p and the result do not point at parts of the same object, the operation is not officially legitimate, and C code is not “supposed” to do it. But you can do it anyway, and it gives precisely the results described by the procedure above. In some special situations it can do something useful, but non-wizards should avoid it.
Here’s a function to offset a pointer value as if it pointed to an object of any given size, by explicitly performing that calculation:
#include <stdint.h> void * ptr_add (void *p, int i, int objsize) { intptr_t p_address = (long) p; intptr_t totalsize = i * objsize; intptr_t new_address = p_address + totalsize; return (void *) new_address; }
This does the same job as p + i
with the proper
pointer type for p. It uses the type intptr_t
, which is
defined in the header file stdint.h. (In practice, long
long
would always work, but it is cleaner to use intptr_t
.)
Next: Pointer Arithmetic Drawbacks, Previous: Pointer Arithmetic Low Level, Up: Pointers [Contents][Index]
The ‘++’ operator adds 1 to a variable. We have seen it for integers (see Increment/Decrement), but it works for pointers too. For instance, suppose we have a series of positive integers, terminated by a zero, and we want to add them all up.
int sum_array_till_0 (int *p) { int sum = 0; for (;;) { /* Fetch the next integer. */ int next = *p++; /* Exit the loop if it’s 0. */ if (next == 0) break; /* Add it into running total. */ sum += next; } return sum; }
The statement ‘break;’ will be explained further on (see break Statement). Used in this way, it immediately exits the surrounding
for
statement.
*p++
parses as *(p++)
, because a postfix operator always
takes precedence over a prefix operator. Therefore, it dereferences
p
, and increments p
afterwards. Incrementing a variable
means adding 1 to it, as in p = p + 1
. Since p
is a
pointer, adding 1 to it advances it by the width of the datum it
points to—in this case, one int
. Therefore, each iteration
of the loop picks up the next integer from the series and puts it into
next
.
This for
-loop has no initialization expression since p
and sum
are already initialized, it has no end-test since the
‘break;’ statement will exit it, and needs no expression to
advance it since that’s done within the loop by incrementing p
and sum
. Thus, those three expressions after for
are
left empty.
Another way to write this function is by keeping the parameter value unchanged and using indexing to access the integers in the table.
int sum_array_till_0_indexing (int *p) { int i; int sum = 0; for (i = 0; ; i++) { /* Fetch the next integer. */ int next = p[i]; /* Exit the loop if it’s 0. */ if (next == 0) break; /* Add it into running total. */ sum += next; } return sum; }
In this program, instead of advancing p
, we advance i
and add it to p
. (Recall that p[i]
means *(p +
i)
.) Either way, it uses the same address to get the next integer.
It makes no difference in this program whether we write i++
or
++i
, because the value is not used. All that matters is the
effect, to increment i
.
The ‘--’ operator also works on pointers; it can be used to scan backwards through an array, like this:
int after_last_nonzero (int *p, int len) { /* Set upq
to point just after the last array element. */ int *q = p + len; while (q != p) /* Stepq
back until it reaches a nonzero element. */ if (*--q != 0) /* Return the index of the element after that nonzero. */ return q - p + 1; return 0; }
That function returns the length of the nonzero part of the array specified by its arguments; that is, the index of the first zero of the run of zeros at the end.
Next: Pointer-Integer Conversion, Previous: Pointer Increment/Decrement, Up: Pointers [Contents][Index]
Pointer arithmetic is clean and elegant, but it is also the cause of a major security flaw in the C language. Theoretically, it is only valid to adjust a pointer within one object allocated as a unit in memory. However, if you unintentionally adjust a pointer across the bounds of the object and into some other object, the system has no way to detect this error.
A bug which does that can easily result in clobbering part of another
object. For example, with array[-1]
you can read or write the
nonexistent element before the beginning of an array—probably part
of some other data.
Combining pointer arithmetic with casts between pointer types, you can create a pointer that fails to be properly aligned for its type. For example,
int a[2]; char *pa = (char *)a; int *p = (int *)(pa + 1);
gives p
a value pointing to an “integer” that includes part
of a[0]
and part of a[1]
. Dereferencing that with
*p
can cause a fatal SIGSEGV
signal or it can return the
contents of that badly aligned int
(see Signals. If it
“works,” it may be quite slow. It can also cause aliasing
confusions (see Aliasing).
Warning: Using improperly aligned pointers is risky—don’t do it unless it is really necessary.
Next: Printing Pointers, Previous: Pointer Arithmetic Drawbacks, Up: Pointers [Contents][Index]
On modern computers, an address is simply a number. It occupies the
same space as some size of integer. In C, you can convert a pointer
to the appropriate integer types and vice versa, without losing
information. The appropriate integer types are uintptr_t
(an
unsigned type) and intptr_t
(a signed type). Both are defined
in stdint.h.
For instance,
#include <stdint.h> #include <stdio.h> void print_pointer (void *ptr) { uintptr_t converted = (uintptr_t) ptr; printf ("Pointer value is 0x%x\n", (unsigned int) converted); }
The specification ‘%x’ in the template (the first argument) for
printf
means to represent this argument using hexadecimal
notation. It’s cleaner to use uintptr_t
, since hexadecimal
printing treats the number as unsigned, but it won’t actually matter:
all printf
gets to see is the series of bits in the number.
Warning: Converting pointers to integers is risky—don’t do it unless it is really necessary.
Previous: Pointer-Integer Conversion, Up: Pointers [Contents][Index]
To print the numeric value of a pointer, use the ‘%p’ specifier. For example:
void print_pointer (void *ptr) { printf ("Pointer value is %p\n", ptr); }
The specification ‘%p’ works with any pointer type. It prints ‘0x’ followed by the address in hexadecimal, printed as the appropriate unsigned integer type.
A structure is a user-defined data type that holds various fields of data. Each field has a name and a data type specified in the structure’s definition.
Here we define a structure suitable for storing a linked list of integers. Each list item will hold one integer, plus a pointer to the next item.
struct intlistlink { int datum; struct intlistlink *next; };
The structure definition has a type tag so that the code can
refer to this structure. The type tag here is intlistlink
.
The definition refers recursively to the same structure through that
tag.
You can define a structure without a type tag, but then you can’t
refer to it again. That is useful only in some special contexts, such
as inside a typedef
or a union
.
The contents of the structure are specified by the field declarations inside the braces. Each field in the structure needs a declaration there. The fields in one structure definition must have distinct names, but these names do not conflict with any other names in the program.
A field declaration looks just like a variable declaration. You can combine field declarations with the same beginning, just as you can combine variable declarations.
This structure has two fields. One, named datum
, has type
int
and will hold one integer in the list. The other, named
next
, is a pointer to another struct intlistlink
which would be the rest of the list. In the last list item, it would
be NULL
.
This structure definition is recursive, since the type of the
next
field refers to the structure type. Such recursion is not
a problem; in fact, you can use the type struct intlistlink *
before the definition of the type struct intlistlink
itself.
That works because pointers to all kinds of structures really look the
same at the machine level.
After defining the structure, you can declare a variable of type
struct intlistlink
like this:
struct intlistlink foo;
The structure definition itself can serve as the beginning of a variable declaration, so you can declare variables immediately after, like this:
struct intlistlink { int datum; struct intlistlink *next; } foo;
But that is ugly. It is almost always clearer to separate the definition of the structure from its uses.
Declaring a structure type inside a block (see Blocks) limits the scope of the structure type name to that block. That means the structure type is recognized only within that block. Declaring it in a function parameter list, as here,
int f (struct foo {int a, b} parm);
(assuming that struct foo
is not already defined) limits the
scope of the structure type struct foo
to that parameter list;
that is basically useless, so it triggers a warning.
Standard C requires at least one field in a structure. GNU C does not require this.
| • Referencing Fields | Accessing field values in a structure object. | |
| • Dynamic Memory Allocation | Allocating space for objects while the program is running. | |
| • Field Offset | Memory layout of fields within a structure. | |
| • Structure Layout | Planning the memory layout of fields. | |
| • Packed Structures | Packing structure fields as close as possible. | |
| • Bit Fields | Dividing integer fields into fields with fewer bits. | |
| • Bit Field Packing | How bit fields pack together in integers. | |
| • const Fields | Making structure fields immutable. | |
| • Zero Length | Zero-length array as a variable-length object. | |
| • Flexible Array Fields | Another approach to variable-length objects. | |
| • Overlaying Structures | Casting one structure type over an object of another structure type. | |
| • Structure Assignment | Assigning values to structure objects. | |
| • Unions | Viewing the same object in different types. | |
| • Packing With Unions | Using a union type to pack various types into the same memory space. | |
| • Cast to Union | Casting a value one of the union’s alternative types to the type of the union itself. | |
| • Structure Constructors | Building new structure objects. | |
| • Unnamed Types as Fields | Fields’ types do not always need names. | |
| • Incomplete Types | Types which have not been fully defined. | |
| • Intertwined Incomplete Types | Defining mutually-recursive structue types. | |
| • Type Tags | Scope of structure and union type tags. |
Next: Dynamic Memory Allocation, Up: Structures [Contents][Index]
To make a structure useful, there has to be a way to examine and store
its fields. The ‘.’ (period) operator does that; its use looks
like object.field
.
Given this structure and variable,
struct intlistlink { int datum; struct intlistlink *next; }; struct intlistlink foo;
you can write foo.datum
and foo.next
to refer to the two
fields in the value of foo
. These fields are lvalues, so you
can store values into them, and read the values out again.
Most often, structures are dynamically allocated (see the next
section), and we refer to the objects via pointers.
(*p).field
is somewhat cumbersome, so there is an
abbreviation: p->field
. For instance, assume the program
contains this declaration:
struct intlistlink *ptr;
You can write ptr->datum
and ptr->next
to refer
to the two fields in the object that ptr
points to.
If a unary operator precedes an expression using ‘->’, the ‘->’ nests inside:
-ptr->datum is equivalent to -(ptr->datum)
You can intermix ‘->’ and ‘.’ without parentheses, as shown here:
struct { double d; struct intlistlink l; } foo; …foo.l.next->next->datum…
Next: Field Offset, Previous: Referencing Fields, Up: Structures [Contents][Index]
To allocate an object dynamically, call the library function
malloc
(see The GNU C Library in The GNU C Library
Reference Manual). Here is how to allocate an object of type
struct intlistlink
. To make this code work, include the file
stdlib.h, like this:
#include <stddef.h> /* DefinesNULL
. */ #include <stdlib.h> /* Declaresmalloc
. */ … struct intlistlink * alloc_intlistlink () { struct intlistlink *p; p = malloc (sizeof (struct intlistlink)); if (p == NULL) fatal ("Ran out of storage"); /* Initialize the contents. */ p->datum = 0; p->next = NULL; return p; }
malloc
returns void *
, so the assignment to p
will automatically convert it to type struct intlistlink *
.
The return value of malloc
is always sufficiently aligned
(see Type Alignment) that it is valid for any data type.
The test for p == NULL
is necessary because malloc
returns a null pointer if it cannot get any storage. We assume that
the program defines the function fatal
to report a fatal error
to the user.
Here’s how to add one more integer to the front of such a list:
struct intlistlink *my_list = NULL; void add_to_mylist (int my_int) { struct intlistlink *p = alloc_intlistlink (); p->datum = my_int; p->next = mylist; mylist = p; }
The way to free the objects is by calling free
. Here’s
a function to free all the links in one of these lists:
void free_intlist (struct intlistlink *p) { while (p) { struct intlistlink *q = p; p = p->next; free (q); } }
We must extract the next
pointer from the object before freeing
it, because free
can clobber the data that was in the object.
For the same reason, the program must not use the list any more after
freeing its elements. To make sure it won’t, it is best to clear out
the variable where the list was stored, like this:
free_intlist (mylist); mylist = NULL;
Next: Structure Layout, Previous: Dynamic Memory Allocation, Up: Structures [Contents][Index]
To determine the offset of a given field field in a structure
type type, use the macro offsetof
, which is defined in
the file stddef.h. It is used like this:
offsetof (type, field)
Here is an example:
struct foo
{
int element;
struct foo *next;
};
offsetof (struct foo, next)
/* On most machines that is 4. It may be 8. */
Next: Packed Structures, Previous: Field Offset, Up: Structures [Contents][Index]
The rest of this chapter covers advanced topics about structures. If you are just learning C, you can skip it.
The precise layout of a struct
type is crucial when using it to
overlay hardware registers, to access data structures in shared
memory, or to assemble and disassemble packets for network
communication. It is also important for avoiding memory waste when
the program makes many objects of that type. However, the layout
depends on the target platform. Each platform has conventions for
structure layout, which compilers need to follow.
Here are the conventions used on most platforms.
The structure’s fields appear in the structure layout in the order they are declared. When possible, consecutive fields occupy consecutive bytes within the structure. However, if a field’s type demands more alignment than it would get that way, C gives it the alignment it requires by leaving a gap after the previous field.
Once all the fields have been laid out, it is possible to determine the structure’s alignment and size. The structure’s alignment is the maximum alignment of any of the fields in it. Then the structure’s size is rounded up to a multiple of its alignment. That may require leaving a gap at the end of the structure.
Here are some examples, where we assume that char
has size and
alignment 1 (always true), and int
has size and alignment 4
(true on most kinds of computers):
struct foo { char a, b; int c; };
This structure occupies 8 bytes, with an alignment of 4. a
is
at offset 0, b
is at offset 1, and c
is at offset 4.
There is a gap of 2 bytes before c
.
Contrast that with this structure:
struct foo { char a; int c; char b; };
This structure has size 12 and alignment 4. a
is at offset 0,
c
is at offset 4, and b
is at offset 8. There are two
gaps: three bytes before c
, and three bytes at the end.
These two structures have the same contents at the C level, but one takes 8 bytes and the other takes 12 bytes due to the ordering of the fields. A reliable way to avoid this sort of wastage is to order the fields by size, biggest fields first.
Next: Bit Fields, Previous: Structure Layout, Up: Structures [Contents][Index]
In GNU C you can force a structure to be laid out with no gaps by
adding __attribute__((packed))
after struct
(or at the
end of the structure type declaration). Here’s an example:
struct __attribute__((packed)) foo { char a; int c; char b; };
Without __attribute__((packed))
, this structure occupies 12
bytes (as described in the previous section), assuming 4-byte
alignment for int
. With __attribute__((packed))
, it is
only 6 bytes long—the sum of the lengths of its fields.
Use of __attribute__((packed))
often results in fields that
don’t have the normal alignment for their types. Taking the address
of such a field can result in an invalid pointer because of its
improper alignment. Dereferencing such a pointer can cause a
SIGSEGV
signal on a machine that doesn’t, in general, allow
unaligned pointers.
See Attributes.
Next: Bit Field Packing, Previous: Packed Structures, Up: Structures [Contents][Index]
A structure field declaration with an integer type can specify the number of bits the field should occupy. We call that a bit field. These are useful because consecutive bit fields are packed into a larger storage unit. For instance,
unsigned char opcode: 4;
specifies that this field takes just 4 bits. Since it is unsigned, its possible values range from 0 to 15. A signed field with 4 bits, such as this,
signed char small: 4;
can hold values from -8 to 7.
You can subdivide a single byte into those two parts by writing
unsigned char opcode: 4; signed char small: 4;
in the structure. With bit fields, these two numbers fit into
a single char
.
Here’s how to declare a one-bit field that can hold either 0 or 1:
unsigned char special_flag: 1;
You can also use the bool
type for bit fields:
bool special_flag: 1;
Except when using bool
(which is always unsigned,
see Boolean Type), always specify signed
or unsigned
for a bit field. There is a default, if that’s not specified: the bit
field is signed if plain char
is signed, except that the option
-funsigned-bitfields forces unsigned as the default. But it
is cleaner not to depend on this default.
Bit fields are special in that you cannot take their address with ‘&’. They are not stored with the size and alignment appropriate for the specified type, so they cannot be addressed through pointers to that type.
Next: const Fields, Previous: Bit Fields, Up: Structures [Contents][Index]
Programs to communicate with low-level hardware interfaces need to define bit fields laid out to match the hardware data. This section explains how to do that.
Consecutive bit fields are packed together, but each bit field must fit within a single object of its specified type. In this example,
unsigned short a : 3, b : 3, c : 3, d : 3, e : 3;
all five fields fit consecutively into one two-byte short
.
They need 15 bits, and one short
provides 16. By contrast,
unsigned char a : 3, b : 3, c : 3, d : 3, e : 3;
needs three bytes. It fits a
and b
into one
char
, but c
won’t fit in that char
(they would
add up to 9 bits). So c
and d
go into a second
char
, leaving a gap of two bits between b
and c
.
Then e
needs a third char
. By contrast,
unsigned char a : 3, b : 3; unsigned int c : 3; unsigned char d : 3, e : 3;
needs only two bytes: the type unsigned int
allows c
to straddle bytes that are in the same word.
You can leave a gap of a specified number of bits by defining a
nameless bit field. This looks like type : nbits;
.
It is allocated space in the structure just as a named bit field would
be allocated.
You can force the following bit field to advance to the following
aligned memory object with type : 0;
.
Both of these constructs can syntactically share type with ordinary bit fields. This example illustrates both:
unsigned int a : 5, : 3, b : 5, : 0, c : 5, : 3, d : 5;
It puts a
and b
into one int
, with a 3-bit gap
between them. Then : 0
advances to the next int
,
so c
and d
fit into that one.
These rules for packing bit fields apply to most target platforms, including all the usual real computers. A few embedded controllers have special layout rules.
Next: Zero Length, Previous: Bit Field Packing, Up: Structures [Contents][Index]
const
FieldsA structure field declared const
cannot be assigned to
(see const). For instance, let’s define this modified version of
struct intlistlink
:
struct intlistlink_ro /* “ro” for read-only. */
{
const int datum;
struct intlistlink *next;
};
This structure can be used to prevent part of the code from modifying
the datum
field:
/*p
has typestruct intlistlink *
. Convert it tostruct intlistlink_ro *
. */ struct intlistlink_ro *q = (struct intlistlink_ro *) p; q->datum = 5; /* Error! */ p->datum = 5; /* Valid since*p
is not astruct intlistlink_ro
. */
A const
field can get a value in two ways: by initialization of
the whole structure, and by making a pointer-to-structure point to an object
in which that field already has a value.
Any const
field in a structure type makes assignment impossible
for structures of that type (see Structure Assignment). That is
because structure assignment works by assigning the structure’s
fields, one by one.
Next: Flexible Array Fields, Previous: const Fields, Up: Structures [Contents][Index]
GNU C allows zero-length arrays. They are useful as the last element
of a structure that is really a header for a variable-length object.
Here’s an example, where we construct a variable-size structure
to hold a line which is this_length
characters long:
struct line { int length; char contents[0]; }; struct line *thisline = ((struct line *) malloc (sizeof (struct line) + this_length)); thisline->length = this_length;
In ISO C90, we would have to give contents
a length of 1, which
means either wasting space or complicating the argument to malloc
.
Next: Overlaying Structures, Previous: Zero Length, Up: Structures [Contents][Index]
The C99 standard adopted a more complex equivalent of zero-length array fields. It’s called a flexible array, and it’s indicated by omitting the length, like this:
struct line { int length; char contents[]; };
The flexible array has to be the last field in the structure, and there must be other fields before it.
Under the C standard, a structure with a flexible array can’t be part of another structure, and can’t be an element of an array.
GNU C allows static initialization of flexible array fields. The effect is to “make the array long enough” for the initializer.
struct f1 { int x; int y[]; } f1 = { 1, { 2, 3, 4 } };
This defines a structure variable named f1
whose type is struct f1
. In C, a variable name or function name
never conflicts with a structure type tag.
Omitting the flexible array field’s size lets the initializer determine it. This is allowed only when the flexible array is defined in the outermost structure and you declare a variable of that structure type. For example:
struct foo { int x; int y[]; }; struct bar { struct foo z; }; struct foo a = { 1, { 2, 3, 4 } }; // Valid. struct bar b = { { 1, { 2, 3, 4 } } }; // Invalid. struct bar c = { { 1, { } } }; // Valid. struct foo d[1] = { { 1 { 2, 3, 4 } } }; // Invalid.
Next: Structure Assignment, Previous: Flexible Array Fields, Up: Structures [Contents][Index]
Be careful about using different structure types to refer to the same memory within one function, because GNU C can optimize code assuming it never does that. See Aliasing. Here’s an example of the kind of aliasing that can cause the problem:
struct a { int size; char *data; }; struct b { int size; char *data; }; struct a foo; struct b *q = (struct b *) &foo;
Here q
points to the same memory that the variable foo
occupies, but they have two different types. The two types
struct a
and struct b
are defined alike, but they are
not the same type. Interspersing references using the two types,
like this,
p->size = 0; q->size = 1; x = p->size;
allows GNU C to assume that p->size
is still zero when it is
copied into x
. The compiler “knows” that q
points to
a struct b
and this cannot overlap with a struct a
.
Other compilers might also do this optimization. The ISO C standard considers such code erroneous, precisely so that this optimization will be valid.
Next: Unions, Previous: Overlaying Structures, Up: Structures [Contents][Index]
Assignment operating on a structure type copies the structure. The left and right operands must have the same type. Here is an example:
#include <stddef.h> /* DefinesNULL
. */ #include <stdlib.h> /* Declaresmalloc
. */ … struct point { double x, y; }; struct point * copy_point (struct point point) { struct point *p = (struct point *) malloc (sizeof (struct point)); if (p == NULL) fatal ("Out of memory"); *p = point; return p; }
Notionally, assignment on a structure type works by copying each of
the fields. Thus, if any of the fields has the const
qualifier, that structure type does not allow assignment:
struct point { const double x, y; };
struct point a, b;
a = b; /* Error! */
Next: Packing With Unions, Previous: Structure Assignment, Up: Structures [Contents][Index]
A union type defines alternative ways of looking at the same piece of memory. Each alternative view is defined with a data type, and identified by a name. A union definition looks like this:
union name
{
alternative declarations…
};
Each alternative declaration looks like a structure field declaration, except that it can’t be a bit field. For instance,
union number { long int integer; double float; }
lets you store either an integer (type long int
) or a floating
point number (type double
) in the same place in memory. The
length and alignment of the union type are the maximum of all the
alternatives—they do not have to be the same. In this union
example, double
probably takes more space than long int
,
but that doesn’t cause a problem in programs that use the union in the
normal way.
The members don’t have to be different in data type. Sometimes each member pertains to a way the data will be used. For instance,
union datum { double latitude; double longitude; double height; double weight; int continent; }
This union holds one of several kinds of data; most kinds are floating
points, but the value can also be a code for a continent which is an
integer. You could use one member of type double
to
access all the values which have that type, but the different member
names will make the program clearer.
The alignment of a union type is the maximum of the alignments of the alternatives. The size of the union type is the maximum of the sizes of the alternatives, rounded up to a multiple of the alignment (because every type’s size must be a multiple of its alignment).
All the union alternatives start at the address of the union itself. If an alternative is shorter than the union as a whole, it occupies the first part of the union’s storage, leaving the last part unused for that alternative.
Warning: if the code stores data using one union alternative and accesses it with another, the results depend on the kind of computer in use. Only wizards should try to do this. However, when you need to do this, a union is a clean way to do it.
Assignment works on any union type by copying the entire value.
Next: Cast to Union, Previous: Unions, Up: Structures [Contents][Index]
Sometimes we design a union with the intention of packing various kinds of objects into a certain amount of memory space. For example.
union bytes8 { long long big_int_elt; double double_elt; struct { int first, second; } two_ints; struct { void *first, *second; } two_ptrs; }; union bytes8 *p;
This union makes it possible to look at 8 bytes of data that p
points to as a single 8-byte integer (p->big_int_elt
), as a
single floating-point number (p->double_elt
), as a pair of
integers (p->two_ints.first
and p->two_ints.second
), or
as a pair of pointers (p->two_ptrs.first
and
p->two_ptrs.second
).
To pack storage with such a union makes assumptions about the sizes of
all the types involved. This particular union was written expecting a
pointer to have the same size as int
. On a machine where one
pointer takes 8 bytes, the code using this union probably won’t work
as expected. The union, as such, will function correctly—if you
store two values through two_ints
and extract them through
two_ints
, you will get the same integers back—but the part of
the program that expects the union to be 8 bytes long could
malfunction, or at least use too much space.
The above example shows one case where a struct
type with no
tag can be useful. Another way to get effectively the same result
is with arrays as members of the union:
union eight_bytes { long long big_int_elt; double double_elt; int two_ints[2]; void *two_ptrs[2]; };
Next: Structure Constructors, Previous: Packing With Unions, Up: Structures [Contents][Index]
In GNU C, you can explicitly cast any of the alternative types to the union type; for instance,
(union eight_bytes) (long long) 5
makes a value of type union eight_bytes
which gets its contents
through the alternative named big_int_elt
.
The value being cast must exactly match the type of the alternative, so this is not valid:
(union eight_bytes) 5 /* Error! 5 is int
. */
A cast to union type looks like any other cast, except that the type
specified is a union type. You can specify the type either with
union tag
or with a typedef name (see Defining Typedef Names).
Using the cast as the right-hand side of an assignment to a variable of union type is equivalent to storing in an alternative of the union:
union foo u; u = (union foo) x means u.i = x u = (union foo) y means u.d = y
You can also use the union cast as a function argument:
void hack (union foo);
…
hack ((union foo) x);
Next: Unnamed Types as Fields, Previous: Cast to Union, Up: Structures [Contents][Index]
You can construct a structure value by writing its type in parentheses, followed by an initializer that would be valid in a declaration for that type. For instance, given this declaration,
struct foo {int a; char b[2];} structure;
you can create a struct foo
value as follows:
((struct foo) {x + y, 'a', 0})
This specifies x + y
for field a
,
the character ‘a’ for field b
’s element 0,
and the null character for field b
’s element 1.
The parentheses around that constructor are to necessary, but we recommend writing them to make the nesting of the containing expression clearer.
You can also show the nesting of the two by writing it like this:
((struct foo) {x + y, {'a', 0} })
Each of those is equivalent to writing the following statement expression (see Statement Exprs):
({ struct foo temp = {x + y, 'a', 0}; temp; })
You can also create a union value this way, but it is not especially useful since that is equivalent to doing a cast:
((union whosis) {value})
is equivalent to
((union whosis) (value))
Next: Incomplete Types, Previous: Structure Constructors, Up: Structures [Contents][Index]
A structure or a union can contain, as fields, unnamed structures and unions. Here’s an example:
struct { int a; union { int b; float c; }; int d; } foo;
You can access the fields of the unnamed union within foo
as if they
were individual fields at the same level as the union definition:
foo.a = 42;
foo.b = 47;
foo.c = 5.25; // Overwrites the value in foo.b
.
foo.d = 314;
Avoid using field names that could cause ambiguity. For example, with this definition:
struct { int a; struct { int a; float b; }; } foo;
it is impossible to tell what foo.a
refers to. GNU C reports
an error when a definition is ambiguous in this way.
Next: Intertwined Incomplete Types, Previous: Unnamed Types as Fields, Up: Structures [Contents][Index]
A type that has not been fully defined is called an incomplete
type. Structure and union types are incomplete when the code makes a
forward reference, such as struct foo
, before defining the
type. An array type is incomplete when its length is unspecified.
You can’t use an incomplete type to declare a variable or field, or
use it for a function parameter or return type. The operators
sizeof
and _Alignof
give errors when used on an
incomplete type.
However, you can define a pointer to an incomplete type, and declare a variable or field with such a pointer type. In general, you can do everything with such pointers except dereference them. For example:
extern void bar (struct mysterious_value *);
void
foo (struct mysterious_value *arg)
{
bar (arg);
}
…
{
struct mysterious_value *p, **q;
p = *q;
foo (p);
}
These examples are valid because the code doesn’t try to understand
what p
points to; it just passes the pointer around.
(Presumably bar
is defined in some other file that really does
have a definition for struct mysterious_value
.) However,
dereferencing the pointer would get an error; that requires a
definition for the structure type.
Next: Type Tags, Previous: Incomplete Types, Up: Structures [Contents][Index]
When several structure types contain pointers to each other, you can define the types in any order because pointers to types that come later are incomplete types. Thus, Here is an example.
/* An employee record points to a group. */ struct employee { char *name; … struct group *group; /* incomplete type. */ … }; /* An employee list points to employees. */ struct employee_list { struct employee *this_one; struct employee_list *next; /* incomplete type. */ … }; /* A group points to one employee_list. */ struct group { char *name; … struct employee_list *employees; … };
Previous: Intertwined Incomplete Types, Up: Structures [Contents][Index]
The name that follows struct
(see Structures), union
(see Unions, or enum
(see Enumeration Types) is called
a type tag. In C, a type tag never conflicts with a variable
name or function name; the type tags have a separate name space.
Thus, there is no name conflict in this code:
struct pair { int a, b; }; int pair = 1;
nor in this one:
struct pair { int a, b; } pair;
where pair
is both a structure type tag and a variable name.
However, struct
, union
, and enum
share the same
name space of tags, so this is a conflict:
struct pair { int a, b; }; enum pair { c, d };
and so is this:
struct pair { int a, b; }; struct pair { int c, d; };
When the code defines a type tag inside a block, the tag’s scope is limited to that block (as for local variables). Two definitions for one type tag do not conflict if they are in different scopes; rather, each is valid in its scope. For example,
struct pair { int a, b; };
void
pair_up_doubles (int len, double array[])
{
struct pair { double a, b; };
…
}
has two definitions for struct pair
which do not conflict. The
one inside the function applies only within the definition of
pair_up_doubles
. Within its scope, that definition
shadows the outer definition.
If struct pair
appears inside the function body, before the
inner definition, it refers to the outer definition—the only one
that has been seen at that point. Thus, in this code,
struct pair { int a, b; };
void
pair_up_doubles (int len, double array[])
{
struct two_pairs { struct pair *p, *q; };
struct pair { double a, b; };
…
}
the structure two_pairs
has pointers to the outer definition of
struct pair
, which is probably not desirable.
To prevent that, you can write struct pair;
inside the function
body as a variable declaration with no variables. This is a
forward declaration of the type tag pair
: it makes the
type tag local to the current block, with the details of the type to
come later. Here’s an example:
void
pair_up_doubles (int len, double array[])
{
/* Forward declaration for pair
. */
struct pair;
struct two_pairs { struct pair *p, *q; };
/* Give the details. */
struct pair { double a, b; };
…
}
However, the cleanest practice is to avoid shadowing type tags.
Next: Enumeration Types, Previous: Structures, Up: Top [Contents][Index]
An array is a data object that holds a series of elements, all of the same data type. Each element is identified by its numeric index within the array.
We presented arrays of numbers in the sample programs early in this manual (see Array Example). However, arrays can have elements of any data type, including pointers, structures, unions, and other arrays.
If you know another programming language, you may suppose that you know all about arrays, but C arrays have special quirks, so in this chapter we collect all the information about arrays in C.
The elements of a C array are allocated consecutively in memory, with no gaps between them. Each element is aligned as required for its data type (see Type Alignment).
| • Accessing Array Elements | How to access individual elements of an array. | |
| • Declaring an Array | How to name and reserve space for a new array. | |
| • Strings | A string in C is a special case of array. | |
| • Array Type Designators | Referring to a specific array type. | |
| • Incomplete Array Types | Naming, but not allocating, a new array. | |
| • Limitations of C Arrays | Arrays are not first-class objects. | |
| • Multidimensional Arrays | Arrays of arrays. | |
| • Constructing Array Values | Assigning values to an entire array at once. | |
| • Arrays of Variable Length | Declaring arrays of non-constant size. |
Next: Declaring an Array, Up: Arrays [Contents][Index]
If the variable a
is an array, the nth element of
a
is a[n]
. You can use that expression to access
an element’s value or to assign to it:
x = a[5]; a[6] = 1;
Since the variable a
is an lvalue, a[n]
is also an
lvalue.
The lowest valid index in an array is 0, not 1, and the highest valid index is one less than the number of elements.
The C language does not check whether array indices are in bounds, so if the code uses an out-of-range index, it will access memory outside the array.
Warning: Using only valid index values in C is the programmer’s responsibility.
Array indexing in C is not a primitive operation: it is defined in
terms of pointer arithmetic and dereferencing. Now that we know
what a[i]
does, we can ask how a[i]
does
its job.
In C, x[y]
is an abbreviation for
*(x+y)
. Thus, a[i]
really means
*(a+i)
. See Pointers and Arrays.
When an expression with array type (such as a
) appears as part
of a larger C expression, it is converted automatically to a pointer
to element zero of that array. For instance, a
in an
expression is equivalent to &a[0]
. Thus, *(a+i)
is
computed as *(&a[0]+i)
.
Now we can analyze how that expression gives us the desired element of
the array. It makes a pointer to element 0 of a
, advances it
by the value of i
, and dereferences that pointer.
Another equivalent way to write the expression is (&a[0])[i]
.
Next: Strings, Previous: Accessing Array Elements, Up: Arrays [Contents][Index]
To make an array declaration, write [length]
after the
name being declared. This construct is valid in the declaration of a
variable, a function parameter, a function value type (the value can’t
be an array, but it can be a pointer to one), a structure field, or a
union alternative.
The surrounding declaration specifies the element type of the array;
that can be any type of data, but not void
or a function type.
For instance,
double a[5];
declares a
as an array of 5 double
s.
struct foo bstruct[length];
declares bstruct
as an array of length
objects of type
struct foo
. A variable array size like this is allowed when
the array is not file-scope.
Other declaration constructs can nest within the array declaration construct. For instance:
struct foo *b[length];
declares b
as an array of length
pointers to
struct foo
. This shows that the length need not be a constant
(see Arrays of Variable Length).
double (*c)[5];
declares c
as a pointer to an array of 5 double
s, and
char *(*f (int))[5];
declares f
as a function taking an int
argument and
returning a pointer to an array of 5 strings (pointers to
char
s).
double aa[5][10];
declares aa
as an array of 5 elements, each of which is an
array of 10 double
s. This shows how to declare a
multidimensional array in C (see Multidimensional Arrays).
All these declarations specify the array’s length, which is needed in these cases in order to allocate storage for the array.
Next: Array Type Designators, Previous: Declaring an Array, Up: Arrays [Contents][Index]
A string in C is a sequence of elements of type char
,
terminated with the null character, the character with code zero.
Programs often need to use strings with specific, fixed contents. To
write one in a C program, use a string constant such as
"Take me to your leader!"
. The data type of a string constant
is char *
. For the full syntactic details of writing string
constants, String Constants.
To declare a place to store a non-constant string, declare an array of
char
. Keep in mind that it must include one extra char
for the terminating null. For instance,
char text[] = { 'H', 'e', 'l', 'l', 'o', 0 };
declares an array named ‘text’ with six elements—five letters and the terminating null character. An equivalent way to get the same result is this,
char text[] = "Hello";
which copies the elements of the string constant, including its terminating null character.
char message[200];
declares an array long enough to hold a string of 199 ASCII characters plus the terminating null character.
When you store a string into message
be sure to check or prove
that the length does not exceed its size. For example,
void set_message (char *text) { int i; for (i = 0; i < sizeof (message); i++) { message[i] = text[i]; if (text[i] == 0) return; } fatal_error ("Message is too long for `message'); }
It’s easy to do this with the standard library function
strncpy
, which fills out the whole destination array (up to a
specified length) with null characters. Thus, if the last character
of the destination is not null, the string did not fit. Many system
libraries, including the GNU C library, hand-optimize strncpy
to run faster than an explicit for
-loop.
Here’s what the code looks like:
void set_message (char *text) { strncpy (message, text, sizeof (message)); if (message[sizeof (message) - 1] != 0) fatal_error ("Message is too long for `message'); }
See The GNU C Library in The GNU C Library Reference Manual, for more information about the standard library functions for operating on strings.
You can avoid putting a fixed length limit on strings you construct or operate on by allocating the space for them dynamically. See Dynamic Memory Allocation.
Next: Incomplete Array Types, Previous: Strings, Up: Arrays [Contents][Index]
Every C type has a type designator, which you make by deleting the variable name and the semicolon from a declaration (see Type Designators). The designators for array types follow this rule, but they may appear surprising.
type int a[5]; designator int [5] type double a[5][3]; designator double [5][3] type struct foo *a[5]; designator struct foo *[5]
Next: Limitations of C Arrays, Previous: Array Type Designators, Up: Arrays [Contents][Index]
An array is equivalent, for most purposes, to a pointer to its zeroth
element. When that is true, the length of the array is irrelevant.
The length needs to be known only for allocating space for the array, or
for sizeof
and typeof
(see Auto Type). Thus, in some
contexts C allows
extern
declaration says how to refer to a variable allocated
elsewhere. It does not need to allocate space for the variable,
so if it is an array, you can omit the length. For example,
extern int foo[];
int func (int foo[])
These declarations are examples of incomplete array types, types
that are not fully specified. The incompleteness makes no difference
for accessing elements of the array, but it matters for some other
things. For instance, sizeof
is not allowed on an incomplete
type.
With multidimensional arrays, only the first dimension can be omitted:
extern struct chesspiece *funnyboard foo[][8];
In other words, the code doesn’t have to say how many rows there are, but it must state how big each row is.
Next: Multidimensional Arrays, Previous: Incomplete Array Types, Up: Arrays [Contents][Index]
Arrays have quirks in C because they are not “first-class objects”: there is no way in C to operate on an array as a unit.
The other composite objects in C, structures and unions, are first-class objects: a C program can copy a structure or union value in an assignment, or pass one as an argument to a function, or make a function return one. You can’t do those things with an array in C. That is because a value you can operate on never has an array type.
An expression in C can have an array type, but that doesn’t produce the array as a value. Instead it is converted automatically to a pointer to the array’s element at index zero. The code can operate on the pointer, and through that on individual elements of the array, but it can’t get and operate on the array as a unit.
There are three exceptions to this conversion rule, but none of them offers a way to operate on the array as a whole.
First, ‘&’ applied to an expression with array type gives you the address of the array, as an array type. However, you can’t operate on the whole array that way—if you apply ‘*’ to get the array back, that expression converts, as usual, to a pointer to its zeroth element.
Second, the operators sizeof
, _Alignof
, and
typeof
do not convert the array to a pointer; they leave it as
an array. But they don’t operate on the array’s data—they only give
information about its type.
Third, a string constant used as an initializer for an array is not converted to a pointer—rather, the declaration copies the contents of that string in that one special case.
You can copy the contents of an array, just not with an
assignment operator. You can do it by calling the library function
memcpy
or memmove
(see The
GNU C Library in The GNU C Library Reference Manual). Also,
when a structure contains just an array, you can copy that structure.
An array itself is an lvalue if it is a declared variable, or part of a structure or union that is an lvalue. When you construct an array from elements (see Constructing Array Values), that array is not an lvalue.
Next: Constructing Array Values, Previous: Limitations of C Arrays, Up: Arrays [Contents][Index]
Strictly speaking, all arrays in C are unidimensional. However, you can create an array of arrays, which is more or less equivalent to a multidimensional array. For example,
struct chesspiece *board[8][8];
declares an array of 8 arrays of 8 pointers to struct
chesspiece
. This data type could represent the state of a chess
game. To access one square’s contents requires two array index
operations, one for each dimension. For instance, you can write
board[row][column]
, assuming row
and column
are variables with integer values in the proper range.
How does C understand board[row][column]
? First of all,
board
is converted automatically to a pointer to the zeroth
element (at index zero) of board
. Adding row
to that
makes it point to the desired element. Thus, board[row]
’s
value is an element of board
—an array of 8 pointers.
However, as an expression with array type, it is converted
automatically to a pointer to the array’s zeroth element. The second
array index operation, [column]
, accesses the chosen element
from that array.
As this shows, pointer-to-array types are meaningful in C. You can declare a variable that points to a row in a chess board like this:
struct chesspiece *(*rowptr)[8];
This points to an array of 8 pointers to struct chesspiece
.
You can assign to it as follows:
rowptr = &board[5];
The dimensions don’t have to be equal in length. Here we declare
statepop
as an array to hold the population of each state in
the United States for each year since 1900:
#define NSTATES 50
{
int nyears = current_year - 1900 + 1;
int statepop[NSTATES][nyears];
…
}
The variable statepop
is an array of NSTATES
subarrays,
each indexed by the year (counting from 1900). Thus, to get the
element for a particular state and year, we must subscript it first
by the number that indicates the state, and second by the index for
the year:
statepop[state][year - 1900]
The subarrays within the multidimensional array are allocated consecutively in memory, and within each subarray, its elements are allocated consecutively in memory. The most efficient way to process all the elements in the array is to scan the last subscript in the innermost loop. This means consecutive accesses go to consecutive memory locations, which optimizes use of the processor’s memory cache. For example:
int total = 0; float average; for (int state = 0; state < NSTATES, ++state) { for (int year = 0; year < nyears; ++year) { total += statepop[state][year]; } } average = total / nyears;
C’s layout for multidimensional arrays is different from Fortran’s layout. In Fortran, a multidimensional array is not an array of arrays; rather, multidimensional arrays are a primitive feature, and it is the first index that varies most rapidly between consecutive memory locations. Thus, the memory layout of a 50x114 array in C matches that of a 114x50 array in Fortran.
Next: Arrays of Variable Length, Previous: Multidimensional Arrays, Up: Arrays [Contents][Index]
You can construct an array from elements by writing them inside braces, and preceding all that with the array type’s designator in parentheses. There is no need to specify the array length, since the number of elements determines that. The constructor looks like this:
(elttype[]) { elements };
Here is an example, which constructs an array of string pointers:
(char *[]) { "x", "y", "z" };
That’s equivalent in effect to declaring an array with the same initializer, like this:
char *array[] = { "x", "y", "z" };
and then using the array.
If all the elements are simple constant expressions, or made up of such, then the compound literal can be coerced to a pointer to its zeroth element and used to initialize a file-scope variable (see File-Scope Variables), as shown here:
char **foo = (char *[]) { "x", "y", "z" };
The data type of foo
is char **
, which is a pointer
type, not an array type. The declaration is equivalent to defining
and then using an array-type variable:
char *nameless_array[] = { "x", "y", "z" }; char **foo = &nameless_array[0];
Previous: Constructing Array Values, Up: Arrays [Contents][Index]
In GNU C, you can declare variable-length arrays like any other arrays, but with a length that is not a constant expression. The storage is allocated at the point of declaration and deallocated when the block scope containing the declaration exits. For example:
#include <stdio.h> /* DefinesFILE
. */ #include <string.h> /* Declaresstr
. */ FILE * concat_fopen (char *s1, char *s2, char *mode) { char str[strlen (s1) + strlen (s2) + 1]; strcpy (str, s1); strcat (str, s2); return fopen (str, mode); }
(This uses some standard library functions; see String and Array Utilities in The GNU C Library Reference Manual.)
The length of an array is computed once when the storage is allocated
and is remembered for the scope of the array in case it is used in
sizeof
.
Warning: don’t allocate a variable-length array if the size might be very large (more than 100,000), or in a recursive function, because that is likely to cause stack overflow. Allocate the array dynamically instead (see Dynamic Memory Allocation).
Jumping or breaking out of the scope of the array name deallocates the storage. Jumping into the scope is not allowed; that gives an error message.
You can also use variable-length arrays as arguments to functions:
struct entry
tester (int len, char data[len][len])
{
…
}
As usual, a function argument declared with an array type is really a pointer to an array that already exists. Calling the function does not allocate the array, so there’s no particular danger of stack overflow in using this construct.
To pass the array first and the length afterward, use a forward declaration in the function’s parameter list (another GNU extension). For example,
struct entry
tester (int len; char data[len][len], int len)
{
…
}
The int len
before the semicolon is a parameter forward
declaration, and it serves the purpose of making the name len
known when the declaration of data
is parsed.
You can write any number of such parameter forward declarations in the parameter list. They can be separated by commas or semicolons, but the last one must end with a semicolon, which is followed by the “real” parameter declarations. Each forward declaration must match a “real” declaration in parameter name and data type. ISO C11 does not support parameter forward declarations.
Next: Defining Typedef Names, Previous: Arrays, Up: Top [Contents][Index]
An enumeration type represents a limited set of integer values, each with a name. It is effectively equivalent to a primitive integer type.
Suppose we have a list of possible emotional states to store in an integer variable. We can give names to these alternative values with an enumeration:
enum emotion_state { neutral, happy, sad, worried, calm, nervous };
(Never mind that this is a simplistic way to classify emotional states; it’s just a code example.)
The names inside the enumeration are called enumerators. The
enumeration type defines them as constants, and their values are
consecutive integers; neutral
is 0, happy
is 1,
sad
is 2, and so on. Alternatively, you can specify values for
the enumerators explicitly like this:
enum emotion_state { neutral = 2, happy = 5, sad = 20, worried = 10, calm = -5, nervous = -300 };
Each enumerator which does not specify a value gets value zero (if it is at the beginning) or the next consecutive integer.
/*neutral
is 0 by default, andworried
is 21 by default. */ enum emotion_state { neutral, happy = 5, sad = 20, worried, calm = -5, nervous = -300 };
If an enumerator is obsolete, you can specify that using it should
cause a warning, by including an attribute in the enumerator’s
declaration. Here is how happy
would look with this
attribute:
happy __attribute__ ((deprecated ("impossible under plutocratic rule"))) = 5,
See Attributes.
You can declare variables with the enumeration type:
enum emotion_state feelings_now;
In the C code itself, this is equivalent to declaring the variable
int
. (If all the enumeration values are positive, it is
equivalent to unsigned int
.) However, declaring it with the
enumeration type has an advantage in debugging, because GDB knows it
should display the current value of the variable using the
corresponding name. If the variable’s type is int
, GDB can
only show the value as a number.
The identifier that follows enum
is called a type tag
since it distinguishes different enumeration types. Type tags are in
a separate name space and belong to scopes like most other names in C.
See Type Tags, for explanation.
You can predeclare an enum
type tag like a structure or union
type tag, like this:
enum foo;
The enum
type is incomplete until you finish defining it.
You can optionally include a trailing comma at the end of a list of enumeration values:
enum emotion_state { neutral, happy, sad, worried, calm, nervous, };
This is useful in some macro definitions, since it enables you to assemble the list of enumerators without knowing which one is last. The extra comma does not change the meaning of the enumeration in any way.
Next: Statements, Previous: Enumeration Types, Up: Top [Contents][Index]
You can define a data type keyword as an alias for any type, and then
use the alias syntactically like a built-in type keyword such as
int
. You do this using typedef
, so these aliases are
also called typedef names.
typedef
is followed by text that looks just like a variable
declaration, but instead of declaring variables it defines data type
keywords.
Here’s how to define fooptr
as a typedef alias for the type
struct foo *
, then declare x
and y
as variables
with that type:
typedef struct foo *fooptr; fooptr x, y;
That declaration is equivalent to the following one:
struct foo *x, *y;
You can define a typedef alias for any type. For instance, this makes
frobcount
an alias for type int
:
typedef int frobcount;
This doesn’t define a new type distinct from int
. Rather,
frobcount
is another name for the type int
. Once the
variable is declared, it makes no difference which name the
declaration used.
There is a syntactic difference, however, between frobcount
and
int
: A typedef name cannot be used with
signed
, unsigned
, long
or short
. It has
to specify the type all by itself. So you can’t write this:
unsigned frobcount f1; /* Error! */
But you can write this:
typedef unsigned int unsigned_frobcount; unsigned_frobcount f1;
In other words, a typedef name is not an alias for a keyword
such as int
. It stands for a type, and that could be
the type int
.
Typedef names are in the same namespace as functions and variables, so you can’t use the same name for a typedef and a function, or a typedef and a variable. When a typedef is declared inside a code block, it is in scope only in that block.
Warning: Avoid defining typedef names that end in ‘_t’, because many of these have standard meanings.
You can redefine a typedef name to the exact same type as its first definition, but you cannot redefine a typedef name to a different type, even if the two types are compatible. For example, this is valid:
typedef int frobcount; typedef int frotzcount; typedef frotzcount frobcount; typedef frobcount frotzcount;
because each typedef name is always defined with the same type
(int
), but this is not valid:
enum foo {f1, f2, f3}; typedef enum foo frobcount; typedef int frobcount;
Even though the type enum foo
is compatible with int
,
they are not the same type.
Next: Variables, Previous: Defining Typedef Names, Up: Top [Contents][Index]
A statement specifies computations to be done for effect; it does not produce a value, as an expression would. In general a statement ends with a semicolon (‘;’), but blocks (which are statements, more or less) are an exception to that rule. See Blocks.
The places to use statements are inside a block, and inside a complex statement. A complex statement contains one or two components that are nested statements. Each such component must consist of one and only one statement. The way to put multiple statements in such a component is to group them into a block (see Blocks), which counts as one statement.
The following sections describe the various kinds of statement.
| • Expression Statement | Evaluate an expression, as a statement, usually done for a side effect. | |
| • if Statement | Basic conditional execution. | |
| • if-else Statement | Multiple branches for conditional execution. | |
| • Blocks | Grouping multiple statements together. | |
| • return Statement | Return a value from a function. | |
| • Loop Statements | Repeatedly executing a statement or block. | |
| • switch Statement | Multi-way conditional choices. | |
| • switch Example | A plausible example of using switch .
| |
| • Duffs Device | A special way to use switch .
| |
| • Case Ranges | Ranges of values for switch cases.
| |
| • Null Statement | A statement that does nothing. | |
| • goto Statement | Jump to another point in the source code, identified by a label. | |
| • Local Labels | Labels with limited scope. | |
| • Labels as Values | Getting the address of a label. | |
| • Statement Exprs | A series of statements used as an expression. |
Next: if Statement, Up: Statements [Contents][Index]
The most common kind of statement in C is an expression statement. It consists of an expression followed by a semicolon. The expression’s value is discarded, so the expressions that are useful are those that have side effects: assignment expressions, increment and decrement expressions, and function calls. Here are examples of expression statements:
x = 5; /* Assignment expression. */ p++; /* Increment expression. */ printf ("Done\n"); /* Function call expression. */ *p; /* CauseSIGSEGV
signal ifp
is null. */ x + y; /* Useless statement without effect. */
In very unusual circumstances we use an expression statement whose purpose is to get a fault if an address is invalid:
volatile char *p;
…
*p; /* Cause signal if p
is null. */
If the target of p
is not declared volatile
, the
compiler might optimize away the memory access, since it knows that
the value isn’t really used. See volatile.
Next: if-else Statement, Previous: Expression Statement, Up: Statements [Contents][Index]
if
StatementAn if
statement computes an expression to decide
whether to execute the following statement or not.
It looks like this:
if (condition) execute-if-true
The first thing this does is compute the value of condition. If that is true (nonzero), then it executes the statement execute-if-true. If the value of condition is false (zero), it doesn’t execute execute-if-true; instead, it does nothing.
This is a complex statement because it contains a component if-true-substatement that is a nested statement. It must be one and only one statement. The way to put multiple statements there is to group them into a block (see Blocks).
Next: Blocks, Previous: if Statement, Up: Statements [Contents][Index]
if-else
StatementAn if
-else
statement computes an expression to decide
which of two nested statements to execute.
It looks like this:
if (condition) if-true-substatement else if-false-substatement
The first thing this does is compute the value of condition. If that is true (nonzero), then it executes the statement if-true-substatement. If the value of condition is false (zero), then it executes the statement if-false-substatement instead.
This is a complex statement because it contains components if-true-substatement and if-else-substatement that are nested statements. Each must be one and only one statement. The way to put multiple statements in such a component is to group them into a block (see Blocks).
Next: return Statement, Previous: if-else Statement, Up: Statements [Contents][Index]
A block is a construct that contains multiple statements of any kind. It begins with ‘{’ and ends with ‘}’, and has a series of statements and declarations in between. Another name for blocks is compound statements.
Is a block a statement? Yes and no. It doesn’t look like a normal statement—it does not end with a semicolon. But you can use it like a statement; anywhere that a statement is required or allowed, you can write a block and consider that block a statement.
So far it seems that a block is a kind of statement with an unusual syntax. But that is not entirely true: a function body is also a block, and that block is definitely not a statement. The text after a function header is not treated as a statement; only a function body is allowed there, and nothing else would be meaningful there.
In a formal grammar we would have to choose—either a block is a kind of statement or it is not. But this manual is meant for humans, not for parser generators. The clearest answer for humans is, “a block is a statement, in some ways.”
A block that isn’t a function body is called an internal block
or a nested block. You can put a nested block directly inside
another block, but more often the nested block is inside some complex
statement, such as a for
statement or an if
statement.
There are two uses for nested blocks in C:
if
statement is one statement. To put multiple statements there, they
have to be wrapped in a block, like this:
if (x < 0) { printf ("x was negative\n"); x = -x; }
This example (repeated from above) shows a nested block which serves
both purposes: it includes two statements (plus a declaration) in the
body of a while
statement, and it provides the scope for the
declaration of q
.
void free_intlist (struct intlistlink *p) { while (p) { struct intlistlink *q = p; p = p->next; free (q); } }
Next: Loop Statements, Previous: Blocks, Up: Statements [Contents][Index]
return
StatementThe return
statement makes the containing function return
immediately. It has two forms. This one specifies no value to
return:
return;
That form is meant for functions whose return type is void
(see The Void Type). You can also use it in a function that
returns nonvoid data, but that’s a bad idea, since it makes the
function return garbage.
The form that specifies a value looks like this:
return value;
which computes the expression value and makes the function return that. If necessary, the value undergoes type conversion to the function’s declared return value type, which works like assigning the value to a variable of that type.
Next: switch Statement, Previous: return Statement, Up: Statements [Contents][Index]
You can use a loop statement when you need to execute a series of statements repeatedly, making an iteration. C provides several different kinds of loop statements, described in the following subsections.
Every kind of loop statement is a complex statement because contains a component, here called body, which is a nested statement. Most often the body is a block.
| • while Statement | Loop as long as a test expression is true. | |
| • do-while Statement | Execute a loop once, with further looping as long as a test expression is true. | |
| • break Statement | End a loop immediately. | |
| • for Statement | Iterative looping. | |
| • Example of for | An example of iterative looping. | |
| • Omitted for-Expressions | for-loop expression options. | |
| • for-Index Declarations | for-loop declaration options. | |
| • continue Statement | Begin the next cycle of a loop. |
Next: do-while Statement, Up: Loop Statements [Contents][Index]
while
StatementThe while
statement is the simplest loop construct.
It looks like this:
while (test) body
Here, body is a statement (often a nested block) to repeat, and test is the test expression that controls whether to repeat it again. Each iteration of the loop starts by computing test and, if it is true (nonzero), that means the loop should execute body again and then start over.
Here’s an example of advancing to the last structure in a chain of
structures chained through the next
field:
#include <stddef.h> /* Defines NULL
. */
…
while (chain->next != NULL)
chain = chain->next;
This code assumes the chain isn’t empty to start with; if the chain is
empty (that is, if chain
is a null pointer), the code gets a
SIGSEGV
signal trying to dereference that null pointer (see Signals).
Next: break Statement, Previous: while Statement, Up: Loop Statements [Contents][Index]
do-while
StatementThe do
–while
statement is a simple loop construct that
performs the test at the end of the iteration.
do body while (test);
Here, body is a statement (possibly a block) to repeat, and test is an expression that controls whether to repeat it again.
Each iteration of the loop starts by executing body. Then it computes test and, if it is true (nonzero), that means to go back and start over with body. If test is false (zero), then the loop stops repeating and execution moves on past it.
Next: for Statement, Previous: do-while Statement, Up: Loop Statements [Contents][Index]
break
StatementThe break
statement looks like ‘break;’. Its effect is to
exit immediately from the innermost loop construct or switch
statement (see switch Statement).
For example, this loop advances p
until the next null
character or newline.
while (*p)
{
/* End loop if we have reached a newline. */
if (*p == '\n')
break;
p++
}
When there are nested loops, the break
statement exits from the
innermost loop containing it.
struct list_if_tuples
{
struct list_if_tuples next;
int length;
data *contents;
};
void
process_all_elements (struct list_if_tuples *list)
{
while (list)
{
/* Process all the elements in this node’s vector,
stopping when we reach one that is null. */
for (i = 0; i < list->length; i++
{
/* Null element terminates this node’s vector. */
if (list->contents[i] == NULL)
/* Exit the for
loop. */
break;
/* Operate on the next element. */
process_element (list->contents[i]);
}
list = list->next;
}
}
The only way in C to exit from an outer loop is with
goto
(see goto Statement).
Next: Example of for, Previous: break Statement, Up: Loop Statements [Contents][Index]
for
StatementA for
statement uses three expressions written inside a
parenthetical group to define the repetition of the loop. The first
expression says how to prepare to start the loop. The second says how
to test, before each iteration, whether to continue looping. The
third says how to advance, at the end of an iteration, for the next
iteration. All together, it looks like this:
for (start; continue-test; advance) body
The first thing the for
statement does is compute start.
The next thing it does is compute the expression continue-test.
If that expression is false (zero), the for
statement finishes
immediately, so body is executed zero times.
However, if continue-test is true (nonzero), the for
statement executes body, then advance. Then it loops back
to the not-quite-top to test continue-test again. But it does
not compute start again.
Next: Omitted for-Expressions, Previous: for Statement, Up: Loop Statements [Contents][Index]
for
Here is the for
statement from the iterative Fibonacci
function:
int i; for (i = 1; i < n; ++i) /* Ifn
is 1 or less, the loop runs zero times, */ /* sincei < n
is false the first time. */ { /* Now last isfib (i)
and prev isfib (i - 1)
. */ /* Computefib (i + 1)
. */ int next = prev + last; /* Shift the values down. */ prev = last; last = next; /* Now last isfib (i + 1)
and prev isfib (i)
. But that won’t stay true for long, because we are about to increment i. */ }
In this example, start is i = 1
, meaning set i
to
1. continue-test is i < n
, meaning keep repeating the
loop as long as i
is less than n
. advance is
i++
, meaning increment i
by 1. The body is a block
that contains a declaration and two statements.
Next: for-Index Declarations, Previous: Example of for, Up: Loop Statements [Contents][Index]
for
-ExpressionsA fully-fleshed for
statement contains all these parts,
for (start; continue-test; advance) body
but you can omit any of the three expressions inside the parentheses.
The parentheses and the two semicolons are required syntactically, but
the expressions between them may be missing. A missing expression
means this loop doesn’t use that particular feature of the for
statement.
Instead of using start, you can do the loop preparation
before the for
statement: the effect is the same. So we
could have written the beginning of the previous example this way:
int i = 0; for (; i < n; ++i)
instead of this way:
int i; for (i = 0; i < n; ++i)
Omitting continue-test means the loop runs forever (or until something else causes exit from it). Statements inside the loop can test conditions for termination and use ‘break;’ to exit. This is more flexible since you can put those tests anywhere in the loop, not solely at the beginning.
Putting an expression in advance is almost equivalent to writing
it at the end of the loop body; it does almost the same thing. The
only difference is for the continue
statement (see continue Statement). So we could have written this:
for (i = 0; i < n;)
{
…
++i;
}
instead of this:
for (i = 0; i < n; ++i)
{
…
}
The choice is mainly a matter of what is more readable for programmers. However, there is also a syntactic difference: advance is an expression, not a statement. It can’t include loops, blocks, declarations, etc.
Next: continue Statement, Previous: Omitted for-Expressions, Up: Loop Statements [Contents][Index]
for
-Index DeclarationsYou can declare loop-index variables directly in the start
portion of the for
-loop, like this:
for (int i = 0; i < n; ++i)
{
…
}
This kind of start is limited to a single declaration; it can
declare one or more variables, separated by commas, all of which are
the same basetype (int
, in this example):
for (int i = 0, j = 1, *p = NULL; i < n; ++i, ++j, ++p)
{
…
}
The scope of these variables is the for
statement as a whole.
See Variable Declarations for a explanation of basetype.
Variables declared in for
statements should have initializers.
Omitting the initialization gives the variables unpredictable initial
values, so this code is erroneous.
for (int i; i < n; ++i)
{
…
}
Previous: for-Index Declarations, Up: Loop Statements [Contents][Index]
continue
StatementThe continue
statement looks like ‘continue;’, and its
effect is to jump immediately to the end of the innermost loop
construct. If it is a for
-loop, the next thing that happens
is to execute the loop’s advance expression.
For example, this loop increments p
until the next null character
or newline, and operates (in some way not shown) on all the characters
in the line except for spaces. All it does with spaces is skip them.
for (;*p; ++p) { /* End loop if we have reached a newline. */ if (*p == '\n') break; /* Pay no attention to spaces. */ if (*p == ' ') continue; /* Operate on the next character. */ … }
Executing ‘continue;’ skips the loop body but it does not
skip the advance expression, p++
.
We could also write it like this:
for (;*p; ++p) { /* Exit if we have reached a newline. */ if (*p == '\n') break; /* Pay no attention to spaces. */ if (*p != ' ') { /* Operate on the next character. */ … } }
The advantage of using continue
is that it reduces the
depth of nesting.
Contrast continue
with the break
statement. See break Statement.
Next: switch Example, Previous: Loop Statements, Up: Statements [Contents][Index]
switch
StatementThe switch
statement selects code to run according to the value
of an expression. The expression, in parentheses, follows the keyword
switch
. After that come all the cases to select among,
inside braces. It looks like this:
switch (selector)
{
cases…
}
A case can look like this:
case value: statements break;
which means “come here if selector happens to have the value value,” or like this (a GNU C extension):
case rangestart ... rangeend: statements break;
which means “come here if selector happens to have a value between rangestart and rangeend (inclusive).” See Case Ranges.
The values in case
labels must reduce to integer constants.
They can use arithmetic, and enum
constants, but they cannot
refer to data in memory, because they have to be computed at compile
time. It is an error if two case
labels specify the same
value, or ranges that overlap, or if one is a range and the other is a
value in that range.
You can also define a default case to handle “any other value,” like this:
default: statements break;
If the switch
statement has no default:
label, then it
does nothing when the value matches none of the cases.
The brace-group inside the switch
statement is a block, and you
can declare variables with that scope just as in any other block
(see Blocks). However, initializers in these declarations won’t
necessarily be executed every time the switch
statement runs,
so it is best to avoid giving them initializers.
break;
inside a switch
statement exits immediately from
the switch
statement. See break Statement.
If there is no break;
at the end of the code for a case,
execution continues into the code for the following case. This
happens more often by mistake than intentionally, but since this
feature is used in real code, we cannot eliminate it.
Warning: When one case is intended to fall through to the next, write a comment like ‘falls through’ to say it’s intentional. That way, other programmers won’t assume it was an error and “fix” it erroneously.
Consecutive case
statements could, pedantically, be considered
an instance of falling through, but we don’t consider or treat them that
way because they won’t confuse anyone.
Next: Duffs Device, Previous: switch Statement, Up: Statements [Contents][Index]
switch
Here’s an example of using the switch
statement
to distinguish among characters:
struct vp { int vowels, punct; };
struct vp
count_vowels_and_punct (char *string)
{
int c;
int vowels = 0;
int punct = 0;
/* Don’t change the parameter itself. */
/* That helps in debugging. */
char *p = string;
struct vp value;
while (c = *p++)
switch (c)
{
case 'y':
case 'Y':
/* We assume y_is_consonant
will check surrounding
letters to determine whether this y is a vowel. */
if (y_is_consonant (p - 1))
break;
/* Falls through */
case 'a':
case 'e':
case 'i':
case 'o':
case 'u':
case 'A':
case 'E':
case 'I':
case 'O':
case 'U':
vowels++;
break;
case '.':
case ',':
case ':':
case ';':
case '?':
case '!':
case '\"':
case '\'':
punct++;
break;
}
value.vowels = vowels;
value.punct = punct;
return value;
}
Next: Case Ranges, Previous: switch Example, Up: Statements [Contents][Index]
The cases in a switch
statement can be inside other control
constructs. For instance, we can use a technique known as Duff’s
device to optimize this simple function,
void copy (char *to, char *from, int count) { while (count > 0) *to++ = *from++, count--; }
which copies memory starting at from to memory starting at to.
Duff’s device involves unrolling the loop so that it copies
several characters each time around, and using a switch
statement
to enter the loop body at the proper point:
void copy (char *to, char *from, int count) { if (count <= 0) return; int n = (count + 7) / 8; switch (count % 8) { do { case 0: *to++ = *from++; case 7: *to++ = *from++; case 6: *to++ = *from++; case 5: *to++ = *from++; case 4: *to++ = *from++; case 3: *to++ = *from++; case 2: *to++ = *from++; case 1: *to++ = *from++; } while (--n > 0); } }
Next: Null Statement, Previous: Duffs Device, Up: Statements [Contents][Index]
You can specify a range of consecutive values in a single case
label,
like this:
case low ... high:
This has the same effect as the proper number of individual case
labels, one for each integer value from low to high, inclusive.
This feature is especially useful for ranges of ASCII character codes:
case 'A' ... 'Z':
Be careful: with integers, write spaces around the ...
to prevent it from being parsed wrong. For example, write this:
case 1 ... 5:
rather than this:
case 1...5:
Next: goto Statement, Previous: Case Ranges, Up: Statements [Contents][Index]
A null statement is just a semicolon. It does nothing.
A null statement is a placeholder for use where a statement is
grammatically required, but there is nothing to be done. For
instance, sometimes all the work of a for
-loop is done in the
for
-header itself, leaving no work for the body. Here is an
example that searches for the first newline in array
:
for (p = array; *p != '\n'; p++) ;
Next: Local Labels, Previous: Null Statement, Up: Statements [Contents][Index]
goto
Statement and LabelsThe goto
statement looks like this:
goto label;
Its effect is to transfer control immediately to another part of the current function—where the label named label is defined.
An ordinary label definition looks like this:
label:
and it can appear before any statement. You can’t use default
as a label, since that has a special meaning for switch
statements.
An ordinary label doesn’t need a separate declaration; defining it is enough.
Here’s an example of using goto
to implement a loop
equivalent to do
–while
:
{ loop_restart: body if (condition) goto loop_restart; }
The name space of labels is separate from that of variables and functions. Thus, there is no error in using a single name in both ways:
{ int foo; // Variablefoo
. foo: // Labelfoo
. body if (foo > 0) // Variablefoo
. goto foo; // Labelfoo
. }
Blocks have no effect on ordinary labels; each label name is defined
throughout the whole of the function it appears in. It looks strange to
jump into a block with goto
, but it works. For example,
if (x < 0) goto negative; if (y < 0) { negative: printf ("Negative\n"); return; }
If the goto jumps into the scope of a variable, it does not
initialize the variable. For example, if x
is negative,
if (x < 0) goto negative; if (y < 0) { int i = 5; negative: printf ("Negative, and i is %d\n", i); return; }
prints junk because i
was not initialized.
If the block declares a variable-length automatic array, jumping into it gives a compilation error. However, jumping out of the scope of a variable-length array works fine, and deallocates its storage.
A label can’t come directly before a declaration, so the code can’t jump directly to one. For example, this is not allowed:
{ goto foo; foo: int x = 5; bar(&x); }
The workaround is to add a statement, even an empty statement, directly after the label. For example:
{ goto foo; foo: ; int x = 5; bar(&x); }
Likewise, a label can’t be the last thing in a block. The workaround solution is the same: add a semicolon after the label.
These unnecessary restrictions on labels make no sense, and ought in
principle to be removed; but they do only a little harm since labels
and goto
are rarely the best way to write a program.
These examples are all artificial; it would be more natural to
write them in other ways, without goto
. For instance,
the clean way to write the example that prints ‘Negative’ is this:
if (x < 0 || y < 0) { printf ("Negative\n"); return; }
It is hard to construct simple examples where goto
is actually
the best way to write a program. Its rare good uses tend to be in
complex code, thus not apt for the purpose of explaining the meaning
of goto
.
The only good time to use goto
is when it makes the code
simpler than any alternative. Jumping backward is rarely desirable,
because usually the other looping and control constructs give simpler
code. Using goto
to jump forward is more often desirable, for
instance when a function needs to do some processing in an error case
and errors can occur at various different places within the function.
Next: Labels as Values, Previous: goto Statement, Up: Statements [Contents][Index]
In GNU C you can declare local labels in any nested block
scope. A local label is used in a goto
statement just like an
ordinary label, but you can only reference it within the block in
which it was declared.
A local label declaration looks like this:
__label__ label;
or
__label__ label1, label2, …;
Local label declarations must come at the beginning of the block, before any ordinary declarations or statements.
The label declaration declares the label name, but does not define
the label itself. That’s done in the usual way, with
label:
, before one of the statements in the block.
The local label feature is useful for complex macros. If a macro
contains nested loops, a goto
can be useful for breaking out of
them. However, an ordinary label whose scope is the whole function
cannot be used: if the macro can be expanded several times in one
function, the label will be multiply defined in that function. A
local label avoids this problem. For example:
#define SEARCH(value, array, target) \ do { \ __label__ found; \ __auto_type _SEARCH_target = (target); \ __auto_type _SEARCH_array = (array); \ int i, j; \ int value; \ for (i = 0; i < max; i++) \ for (j = 0; j < max; j++) \ if (_SEARCH_array[i][j] == _SEARCH_target) \ { (value) = i; goto found; } \ (value) = -1; \ found:; \ } while (0)
This could also be written using a statement expression (see Statement Exprs):
#define SEARCH(array, target) \ ({ \ __label__ found; \ __auto_type _SEARCH_target = (target); \ __auto_type _SEARCH_array = (array); \ int i, j; \ int value; \ for (i = 0; i < max; i++) \ for (j = 0; j < max; j++) \ if (_SEARCH_array[i][j] == _SEARCH_target) \ { value = i; goto found; } \ value = -1; \ found: \ value; \ })
Ordinary labels are visible throughout the function where they are defined, and only in that function. However, explicitly declared local labels of a block are visible in nested functions declared within that block. See Nested Functions, for details.
See goto Statement.
Next: Statement Exprs, Previous: Local Labels, Up: Statements [Contents][Index]
In GNU C, you can get the address of a label defined in the current
function (or a local label defined in the containing function) with
the unary operator ‘&&’. The value has type void *
. This
value is a constant and can be used wherever a constant of that type
is valid. For example:
void *ptr;
…
ptr = &&foo;
To use these values requires a way to jump to one. This is done
with the computed goto statement5, goto *exp;
. For example,
goto *ptr;
Any expression of type void *
is allowed.
See goto Statement.
| • Label Value Uses | Examples of using label values. | |
| • Label Value Caveats | Limitations of label values. |
Next: Label Value Caveats, Up: Labels as Values [Contents][Index]
One use for label-valued constants is to initialize a static array to serve as a jump table:
static void *array[] = { &&foo, &&bar, &&hack };
Then you can select a label with indexing, like this:
goto *array[i];
Note that this does not check whether the subscript is in bounds—array indexing in C never checks that.
You can make the table entries offsets instead of addresses by subtracting one label from the others. Here is an example:
static const int array[] = { &&foo - &&foo, &&bar - &&foo, &&hack - &&foo }; goto *(&&foo + array[i]);
Using offsets is preferable in shared libraries, as it avoids the need for dynamic relocation of the array elements; therefore, the array can be read-only.
An array of label values or offsets serves a purpose much like that of
the switch
statement. The switch
statement is cleaner,
so use switch
by preference when feasible.
Another use of label values is in an interpreter for threaded code. The labels within the interpreter function can be stored in the threaded code for super-fast dispatching.
Previous: Label Value Uses, Up: Labels as Values [Contents][Index]
Jumping to a label defined in another function does not work. It can cause unpredictable results.
The best way to avoid this is to store label values only in automatic variables, or static variables whose names are declared within the function. Never pass them as arguments.
An optimization known as cloning generates multiple simplified variants of a function’s code, for use with specific fixed arguments. Using label values in certain ways, such as saving the address in one call to the function and using it again in another call, would make cloning give incorrect results. These functions must disable cloning.
Inlining calls to the function would also result in multiple copies of the code, each with its own value of the same label. Using the label in a computed goto is no problem, because the computed goto inhibits inlining. However, using the label value in some other way, such as an indication of where an error occurred, would be optimized wrong. These functions must disable inlining.
To prevent inlining or cloning of a function, specify
__attribute__((__noinline__,__noclone__))
in its definition.
See Attributes.
When a function uses a label value in a static variable initializer, that automatically prevents inlining or cloning the function.
Previous: Labels as Values, Up: Statements [Contents][Index]
A block enclosed in parentheses can be used as an expression in GNU C. This provides a way to use local variables, loops and switches within an expression. We call it a statement expression.
Recall that a block is a sequence of statements surrounded by braces. In this construct, parentheses go around the braces. For example:
({ int y = foo (); int z; if (y > 0) z = y; else z = - y; z; })
is a valid (though slightly more complex than necessary) expression
for the absolute value of foo ()
.
The last statement in the block should be an expression statement; an
expression followed by a semicolon, that is. The value of this
expression serves as the value of statement expression. If the last
statement is anything else, the statement expression’s value is
void
.
This feature is mainly useful in making macro definitions compute each operand exactly once. See Macros and Auto Type.
Statement expressions are not allowed in expressions that must be constant, such as the value for an enumerator, the width of a bit-field, or the initial value of a static variable.
Jumping into a statement expression—with goto
, or using a
switch
statement outside the statement expression—is an
error. With a computed goto
(see Labels as Values), the
compiler can’t detect the error, but it still won’t work.
Jumping out of a statement expression is permitted, but since subexpressions in C are not computed in a strict order, it is unpredictable which other subexpressions will have been computed by then. For example,
foo (), (({ bar1 (); goto a; 0; }) + bar2 ()), baz();
calls foo
and bar1
before it jumps, and never
calls baz
, but may or may not call bar2
. If bar2
does get called, that occurs after foo
and before bar1
.
Next: Type Qualifiers, Previous: Statements, Up: Top [Contents][Index]
Every variable used in a C program needs to be made known by a
declaration. It can be used only after it has been declared.
It is an error to declare a variable name more than once in the same
scope; an exception is that extern
declarations and tentative
definitions can coexist with another declaration of the same
variable.
Variables can be declared anywhere within a block or file. (Older versions of C required that all variable declarations within a block occur before any statements.)
Variables declared within a function or block are local to it. This means that the variable name is visible only until the end of that function or block, and the memory space is allocated only while control is within it.
Variables declared at the top level in a file are called file-scope. They are assigned fixed, distinct memory locations, so they retain their values for the whole execution of the program.
| • Variable Declarations | Name a variable and and reserve space for it. | |
| • Initializers | Assigning inital values to variables. | |
| • Designated Inits | Assigning initial values to array elements at particular array indices. | |
| • Auto Type | Obtaining the type of a variable. | |
| • Local Variables | Variables declared in function definitions. | |
| • File-Scope Variables | Variables declared outside of function definitions. | |
| • Static Local Variables | Variables declared within functions, but with permanent storage allocation. | |
| • Extern Declarations | Declaring a variable which is allocated somewhere else. | |
| • Allocating File-Scope | When is space allocated for file-scope variables? | |
| • auto and register | Historically used storage directions. | |
| • Omitting Types | The bad practice of declaring variables with implicit type. |
Next: Initializers, Up: Variables [Contents][Index]
Here’s what a variable declaration looks like:
keywords basetype decorated-variable [= init];
The keywords specify how to handle the scope of the variable name and the allocation of its storage. Most declarations have no keywords because the defaults are right for them.
C allows these keywords to come before or after basetype, or
even in the middle of it as in unsigned static int
, but don’t
do that—it would surprise other programmers. Always write the
keywords first.
The basetype can be any of the predefined types of C, or a type
keyword defined with typedef
. It can also be struct
tag
, union tag
, or enum tag
. In
addition, it can include type qualifiers such as const
and
volatile
(see Type Qualifiers).
In the simplest case, decorated-variable is just the variable name. That declares the variable with the type specified by basetype. For instance,
int foo;
uses int
as the basetype and foo
as the
decorated-variable. It declares foo
with type
int
.
struct tree_node foo;
declares foo
with type struct tree_node
.
| • Declaring Arrays and Pointers | Declaration syntax for variables of array and pointer types. | |
| • Combining Variable Declarations | More than one variable declaration in a single statement. |
Next: Combining Variable Declarations, Up: Variable Declarations [Contents][Index]
To declare a variable that is an array, write
variable[length]
for decorated-variable:
int foo[5];
To declare a variable that has a pointer type, write
*variable
for decorated-variable:
struct list_elt *foo;
These constructs nest. For instance,
int foo[3][5];
declares foo
as an array of 3 arrays of 5 integers each,
struct list_elt *foo[5];
declares foo
as an array of 5 pointers to structures, and
struct list_elt **foo;
declares foo
as a pointer to a pointer to a structure.
int **(*foo[30])(int, double);
declares foo
as an array of 30 pointers to functions
(see Function Pointers), each of which must accept two arguments
(one int
and one double
) and return type int **
.
void
bar (int size)
{
int foo[size];
…
}
declares foo
as an array of integers with a size specified at
run time when the function bar
is called.
Previous: Declaring Arrays and Pointers, Up: Variable Declarations [Contents][Index]
When multiple declarations have the same keywords and basetype, you can combine them using commas. Thus,
keywords basetype decorated-variable-1 [= init1], decorated-variable-2 [= init2];
is equivalent to
keywords basetype decorated-variable-1 [= init1]; keywords basetype decorated-variable-2 [= init2];
Here are some simple examples:
int a, b; int a = 1, b = 2; int a, *p, array[5]; int a = 0, *p = &a, array[5] = {1, 2};
In the last two examples, a
is an int
, p
is a
pointer to int
, and array
is an array of 5 int
s.
Since the initializer for array
specifies only two elements,
the other three elements are initialized to zero.
Next: Designated Inits, Previous: Variable Declarations, Up: Variables [Contents][Index]
A variable’s declaration, unless it is extern
, should also
specify its initial value. For numeric and pointer-type variables,
the initializer is an expression for the value. If necessary, it is
converted to the variable’s type, just as in an assignment.
You can also initialize a local structure-type (see Structures) or local union-type (see Unions) variable this way, from an expression whose value has the same type. But you can’t initialize an array this way (see Arrays), since arrays are not first-class objects in C (see Limitations of C Arrays) and there is no array assignment.
You can initialize arrays and structures componentwise, with a list of the elements or components. You can initialize a union with any one of its alternatives.
You can omit the size of the array when you declare it, and let the initializer specify the size:
int array[] = { 3, 9, 12 };
{
value }
, where value initializes the first alternative
in the union definition.
For an array of arrays, a structure containing arrays, an array of structures, etc., you can nest these constructs. For example,
struct point { double x, y; }; struct point series[] = { {0, 0}, {1.5, 2.8}, {99, 100.0004} };
You can omit a pair of inner braces if they contain the right number of elements for the sub-value they initialize, so that no elements or fields need to be filled in with zeros. But don’t do that very much, as it gets confusing.
An array of char
can be initialized using a string constant.
Recall that the string constant includes an implicit null character at
the end (see String Constants). Using a string constant as
initializer means to use its contents as the initial values of the
array elements. Here are examples:
char text[6] = "text!"; /* Includes the null. */ char text[5] = "text!"; /* Excludes the null. */ char text[] = "text!"; /* Gets length 6. */ char text[] = { 't', 'e', 'x', 't', '!', 0 }; /* same as above. */ char text[] = { "text!" }; /* Braces are optional. */
and this kind of initializer can be nested inside braces to initialize
structures or arrays that contain a char
-array.
In like manner, you can use a wide string constant to initialize
an array of wchar_t
.
Next: Auto Type, Previous: Initializers, Up: Variables [Contents][Index]
In a complex structure or long array, it’s useful to indicate which field or element we are initializing.
To designate specific array elements during initialization, include the array index in brackets, and an assignment operator, for each element:
int foo[10] = { [3] = 42, [7] = 58 };
This does the same thing as:
int foo[10] = { 0, 0, 0, 42, 0, 0, 0, 58, 0, 0 };
The array initialization can include non-designated element values alongside designated indices; these follow the expected ordering of the array initialization, so that
int foo[10] = { [3] = 42, 43, 44, [7] = 58 };
does the same thing as:
int foo[10] = { 0, 0, 0, 42, 43, 44, 0, 58, 0, 0 };
Note that you can only use constant expressions as array index values, not variables.