const
Fieldsif
Statementif-else
Statementreturn
Statementswitch
Statementswitch
goto
Statement and Labels__auto_type
extern
Declarationsauto
and register
Next: The First Example [Contents][Index]
This manual explains the C language for use with the GNU Compiler Collection (GCC) on the GNU/Linux system and other systems. We refer to this dialect as GNU C. If you already know C, you can use this as a reference manual.
If you understand basic concepts of programming but know nothing about C, you can read this manual sequentially from the beginning to learn the C language.
If you are a beginner to programming, we recommend you first learn a language with automatic garbage collection and no explicit pointers, rather than starting with C. Good choices include Lisp, Scheme, Python and Java. C’s explicit pointers mean that programmers must be careful to avoid certain kinds of errors.
C is a venerable language; it was first used in 1973. The GNU C Compiler, which was subsequently extended into the GNU Compiler Collection, was first released in 1987. Other important languages were designed based on C: once you know C, it gives you a useful base for learning C++, C#, Java, Scala, D, Go, and more.
The special advantage of C is that it is fairly simple while allowing close access to the computer’s hardware, which previously required writing in assembler language to describe the individual machine instructions. Some have called C a “high-level assembler language” because of its explicit pointers and lack of automatic management of storage. As one wag put it, “C combines the power of assembler language with the convenience of assembler language.” However, C is far more portable, and much easier to read and write, than assembler language.
This manual describes the GNU C language supported by the GNU Compiler Collection, as of roughly 2017. Please inform us of any changes needed to match the current version of GNU C.
When a construct may be absent or work differently in other C compilers, we say so. When it is not part of ISO standard C, we say it is a “GNU C extension,” because it is useful to know that. However, standards and other dialects are secondary topics for this manual. For simplicity’s sake, we keep those notes short, unless it is vital to say more.
Likewise, we hardly mention C++ or other languages that the GNU Compiler Collection supports. We hope this manual will serve as a base for writing manuals for those languages, but languages so different can’t share one common manual.
Some aspects of the meaning of C programs depend on the target platform: which computer, and which operating system, the compiled code will run on. Where this is the case, we say so.
The C language provides no built-in facilities for performing such common operations as input/output, memory management, string manipulation, and the like. Instead, these facilities are defined in a standard library, which is automatically available in every C program. See The GNU C Library in The GNU C Library Reference Manual.
This manual incorporates the former GNU C Preprocessor Manual, which was among the earliest GNU Manuals. It also uses some text from the earlier GNU C Manual that was written by Trevis Rothwell and James Youngman.
GNU C has many obscure features, each one either for historical compatibility or meant for very special situations. We have left them to a companion manual, the GNU C Obscurities Manual, which will be published digitally later.
Please report errors and suggestions to<EMAIL_ADDRESS>| • The First Example | Getting started with basic C code. | |
| • Complete Program | A whole example program that can be compiled and run. | |
| • Storage | Basic layout of storage; bytes. | |
| • Beyond Integers | Exploring different numeric types. | |
| • Lexical Syntax | The various lexical components of C programs. | |
| • Arithmetic | Numeric computations. | |
| • Assignment Expressions | Storing values in variables. | |
| • Execution Control Expressions | Expressions combining values in various ways. | |
| • Binary Operator Grammar | An overview of operator precedence. | |
| • Order of Execution | The order of program execution. | |
| • Primitive Types | More details about primitive data types. | |
| • Constants | Explicit constant values: details and examples. | |
| • Type Size | The memory space occupied by a type. | |
| • Pointers | Creating and manipulating memory pointers. | |
| • Structures | Compound data types built by grouping other types. | |
| • Arrays | Creating and manipulating arrays. | |
| • Enumeration Types | Sets of integers with named values. | |
| • Defining Typedef Names | Using typedef to define type names.
| |
| • Statements | Controling program flow. | |
| • Variables | Details about declaring, initializing, and using variables. | |
| • Type Qualifiers | Mark variables for certain intended uses. | |
| • Functions | Declaring, defining, and calling functions. | |
| • Compatible Types | How to tell if two types are compatible with each other. | |
| • Type Conversions | Converting between types. | |
| • Scope | Different categories of identifier scope. | |
| • Preprocessing | Using the GNU C preprocessor. | |
| • Integers in Depth | How integer numbers are represented. | |
| • Floating Point in Depth | How floating-point numbers are represented. | |
| • Compilation | How to compile multi-file programs. | |
| • Directing Compilation | Operations that affect compilation but don’t change the program. | |
Appendices | ||
|---|---|---|
| • Type Alignment | Where in memory a type can validly start. | |
| • Aliasing | Accessing the same data in two types. | |
| • Digraphs | Two-character aliases for some characters. | |
| • Attributes | Specifying additional information in a declaration. | |
| • Signals | Fatal errors triggered in various scenarios. | |
| • GNU Free Documentation License | The license for this manual. | |
| • Symbol Index | Keyword and symbol index. | |
| • Concept Index | Detailed topical index. | |
— The Detailed Node Listing — | ||
| • Recursive Fibonacci | Writing a simple function recursively. | |
| • Stack | Each function call uses space in the stack. | |
| • Iterative Fibonacci | Writing the same function iteratively. | |
| • Complete Example | Turn the simple function into a full program. | |
| • Complete Explanation | Explanation of each part of the example. | |
| • Complete Line-by-Line | Explaining each line of the example. | |
| • Compile Example | Using GCC to compile the example. | |
| • Float Example | A function that uses floating-point numbers. | |
| • Array Example | A function that works with arrays. | |
| • Array Example Call | How to call that function. | |
| • Array Example Variations | Different ways to write the call example. | |
Lexical Syntax | ||
| • English | Write programs in English! | |
| • Characters | The characters allowed in C programs. | |
| • Whitespace | The particulars of whitespace characters. | |
| • Comments | How to include comments in C code. | |
| • Identifiers | How to form identifiers (names). | |
| • Operators/Punctuation | Characters used as operators or punctuation. | |
| • Line Continuation | Splitting one line into multiple lines. | |
| • Digraphs | Two-character substitutes for some characters. | |
Arithmetic | ||
| • Basic Arithmetic | Addition, subtraction, multiplication, and division. | |
| • Integer Arithmetic | How C performs arithmetic with integer values. | |
| • Integer Overflow | When an integer value exceeds the range of its type. | |
| • Mixed Mode | Calculating with both integer values and floating-point values. | |
| • Division and Remainder | How integer division works. | |
| • Numeric Comparisons | Comparing numeric values for equality or order. | |
| • Shift Operations | Shift integer bits left or right. | |
| • Bitwise Operations | Bitwise conjunction, disjunction, negation. | |
Assignment Expressions | ||
| • Simple Assignment | The basics of storing a value. | |
| • Lvalues | Expressions into which a value can be stored. | |
| • Modifying Assignment | Shorthand for changing an lvalue’s contents. | |
| • Increment/Decrement | Shorthand for incrementing and decrementing an lvalue’s contents. | |
| • Postincrement/Postdecrement | Accessing then incrementing or decrementing. | |
| • Assignment in Subexpressions | How to avoid ambiguity. | |
| • Write Assignments Separately | Write assignments as separate statements. | |
Execution Control Expressions | ||
| • Logical Operators | Logical conjunction, disjunction, negation. | |
| • Logicals and Comparison | Logical operators with comparison operators. | |
| • Logicals and Assignments | Assignments with logical operators. | |
| • Conditional Expression | An if/else construct inside expressions. | |
| • Comma Operator | Build a sequence of subexpressions. | |
Order of Execution | ||
| • Reordering of Operands | Operations in C are not necessarily computed in the order they are written. | |
| • Associativity and Ordering | Some associative operations are performed in a particular order; others are not. | |
| • Sequence Points | Some guarantees about the order of operations. | |
| • Postincrement and Ordering | Ambiguous excution order with postincrement. | |
| • Ordering of Operands | Evaluation order of operands and function arguments. | |
| • Optimization and Ordering | Compiler optimizations can reorder operations only if it has no impact on program results. | |
Primitive Data Types | ||
| • Integer Types | Description of integer types. | |
| • Floating-Point Data Types | Description of floating-point types. | |
| • Complex Data Types | Description of complex number types. | |
| • The Void Type | A type indicating no value at all. | |
| • Other Data Types | A brief summary of other types. | |
Constants | ||
| • Integer Constants | Literal integer values. | |
| • Integer Const Type | Types of literal integer values. | |
| • Floating Constants | Literal floating-point values. | |
| • Imaginary Constants | Literal imaginary number values. | |
| • Invalid Numbers | Avoiding preprocessing number misconceptions. | |
| • Character Constants | Literal character values. | |
| • Unicode Character Codes | Unicode characters represented in either UTF-16 or UTF-32. | |
| • Wide Character Constants | Literal characters values larger than 8 bits. | |
| • String Constants | Literal string values. | |
| • UTF-8 String Constants | Literal UTF-8 string values. | |
| • Wide String Constants | Literal string values made up of 16- or 32-bit characters. | |
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.
| |
Structures | ||
| • 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. | |
Arrays | ||
| • 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. | |
| • 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. | |
Statements | ||
| • 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. | |
Variables | ||
| • 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. | |
Type Qualifiers | ||
| • const | Variables whose values don’t change. | |
| • volatile | Variables whose values may be accessed or changed outside of the control of this program. | |
| • restrict Pointers | Restricted pointers for code optimization. | |
| • restrict Pointer Example | Example of how that works. | |
Functions | ||
| • Function Definitions | Writing the body of a function. | |
| • Function Declarations | Declaring the interface of a function. | |
| • Function Calls | Using functions. | |
| • Function Call Semantics | Call-by-value argument passing. | |
| • Function Pointers | Using references to functions. | |
| • The main Function | Where execution of a GNU C program begins. | |
Type Conversions | ||
| • Explicit Type Conversion | Casting a value from one type to another. | |
| • Assignment Type Conversions | Automatic conversion by assignment operation. | |
| • Argument Promotions | Automatic conversion of function parameters. | |
| • Operand Promotions | Automatic conversion of arithmetic operands. | |
| • Common Type | When operand types differ, which one is used? | |
Scope | ||
| • Scope | Different categories of identifier scope. | |
Preprocessing | ||
| • Preproc Overview | Introduction to the C preprocessor. | |
| • Directives | The form of preprocessor directives. | |
| • Preprocessing Tokens | The lexical elements of preprocessing. | |
| • Header Files | Including one source file in another. | |
| • Macros | Macro expansion by the preprocessor. | |
| • Conditionals | Controling whether to compile some lines or ignore them. | |
| • Diagnostics | Reporting warnings and errors. | |
| • Line Control | Reporting source line numbers. | |
| • Null Directive | A preprocessing no-op. | |
Integers in Depth | ||
| • Integer Representations | How integer values appear in memory. | |
| • Maximum and Minimum Values | Value ranges of integer types. | |
Floating Point in Depth | ||
| • Floating Representations | How floating-point values appear in memory. | |
| • Floating Type Specs | Precise details of memory representations. | |
| • Special Float Values | Infinity, Not a Number, and Subnormal Numbers. | |
| • Invalid Optimizations | Don’t mess up non-numbers and signed zeros. | |
| • Exception Flags | Handling certain conditions in floating point. | |
| • Exact Floating-Point | Not all floating calculations lose precision. | |
| • Rounding | When a floating result can’t be represented exactly in the floating-point type in use. | |
| • Rounding Issues | Avoid magnifying rounding errors. | |
| • Significance Loss | Subtracting numbers that are almost equal. | |
| • Fused Multiply-Add | Taking advantage of a special floating-point instruction for faster execution. | |
| • Error Recovery | Determining rounding errors. | |
| • Exact Floating Constants | Precisely specified floating-point numbers. | |
| • Handling Infinity | When floating calculation is out of range. | |
| • Handling NaN | What floating calculation is undefined. | |
| • Signed Zeros | Positive zero vs. negative zero. | |
| • Scaling by the Base | A useful exact floating-point operation. | |
| • Rounding Control | Specifying some rounding behaviors. | |
| • Machine Epsilon | The smallest number you can add to 1.0 and get a sum which is larger than 1.0. | |
| • Complex Arithmetic | Details of arithmetic with complex numbers. | |
| • Round-Trip Base Conversion | What happens between base-2 and base-10. | |
| • Further Reading | References for floating-point numbers. | |
Directing Compilation | ||
| • Pragmas | Controling compilation of some constructs. | |
| • Static Assertions | Compile-time tests for conditions. | |
Next: Complete Program, Previous: Top, Up: Top [Contents][Index]
This chapter presents the source code for a very simple C program and uses it to explain a few features of the language. If you already know the basic points of C presented in this chapter, you can skim it or skip it.
| • Recursive Fibonacci | Writing a simple function recursively. | |
| • Stack | Each function call uses space in the stack. | |
| • Iterative Fibonacci | Writing the same function iteratively. |
Next: Stack, Up: The First Example [Contents][Index]
To introduce the most basic features of C, let’s look at code for a simple mathematical function that does calculations on integers. This function calculates the nth number in the Fibonacci series, in which each number is the sum of the previous two: 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, ….
int
fib (int n)
{
if (n <= 2) /* This avoids infinite recursion. */
return 1;
else
return fib (n - 1) + fib (n - 2);
}
This very simple program illustrates several features of C:
n
, referred to as the variable n
inside the function body. See Function Parameter Variables.
A function definition uses parameters to refer to the argument
values provided in a call to that function.
fib (n - 1)
calls the
function fib
, passing as its argument the value n - 1
.
See Function Calls.
return
statement and the
if
…else
statement. See Statements.
fib
calls itself; that is called a
recursive call. These are valid in C, and quite common.
The fib
function would not be useful if it didn’t return.
Thus, recursive definitions, to be of any use, must avoid infinite
recursion.
This function definition prevents infinite recursion by specially
handling the case where n
is two or less. Thus the maximum
depth of recursive calls is less than n
.
| • Function Header | The function’s name and how it is called. | |
| • Function Body | Declarations and statements that implement the function. |
Next: Function Body, Up: Recursive Fibonacci [Contents][Index]
In our example, the first two lines of the function definition are the header. Its purpose is to state the function’s name and say how it is called:
int fib (int n)
says that the function returns an integer (type int
), its name is
fib
, and it takes one argument named n
which is also an
integer. (Data types will be explained later, in Primitive Types.)
Previous: Function Header, Up: Recursive Fibonacci [Contents][Index]
The rest of the function definition is called the function body. Like every function body, this one starts with ‘{’, ends with ‘}’, and contains zero or more statements and declarations. Statements specify actions to take, whereas declarations define names of variables, functions, and so on. Each statement and each declaration ends with a semicolon (‘;’).
Statements and declarations often contain expressions; an expression is a construct whose execution produces a value of some data type, but may also take actions through “side effects” that alter subsequent execution. A statement, by contrast, does not have a value; it affects further execution of the program only through the actions it takes.
This function body contains no declarations, and just one statement, but that one is a complex statement in that it contains nested statements. This function uses two kinds of statements:
return
The return
statement makes the function return immediately.
It looks like this:
return value;
Its meaning is to compute the expression value and exit the function, making it return whatever value that expression produced. For instance,
return 1;
returns the integer 1 from the function, and
return fib (n - 1) + fib (n - 2);
returns a value computed by performing two function calls as specified and adding their results.
if
…else
The if
…else
statement is a conditional.
Each time it executes, it chooses one of its two substatements to execute
and ignores the other. It looks like this:
if (condition) if-true-statement else if-false-statement
Its meaning is to compute the expression condition and, if it’s “true,” execute if-true-statement. Otherwise, execute if-false-statement. See if-else Statement.
Inside the if
…else
statement, condition is
simply an expression. It’s considered “true” if its value is
nonzero. (A comparison operation, such as n <= 2
, produces the
value 1 if it’s “true” and 0 if it’s “false.” See Numeric Comparisons.) Thus,
if (n <= 2) return 1; else return fib (n - 1) + fib (n - 2);
first tests whether the value of n
is less than or equal to 2.
If so, the expression n <= 2
has the value 1. So execution
continues with the statement
return 1;
Otherwise, execution continues with this statement:
return fib (n - 1) + fib (n - 2);
Each of these statements ends the execution of the function and provides a value for it to return. See return Statement.
Calculating fib
using ordinary integers in C works only for
n < 47, because the value of fib (47)
is too large to fit
in type int
. The addition operation that tries to add
fib (46)
and fib (45)
cannot deliver the correct result.
This occurrence is called integer overflow.
Overflow can manifest itself in various ways, but one thing that can’t possibly happen is to produce the correct value, since that can’t fit in the space for the value. See Integer Overflow.
See Functions, for a full explanation about functions.
Next: Iterative Fibonacci, Previous: Recursive Fibonacci, Up: The First Example [Contents][Index]
Recursion has a drawback: there are limits to how many nested function calls a program can make. In C, each function call allocates a block of memory which it uses until the call returns. C allocates these blocks consecutively within a large area of memory known as the stack, so we refer to the blocks as stack frames.
The size of the stack is limited; if the program tries to use too much, that causes the program to fail because the stack is full. This is called stack overflow.
Stack overflow on GNU/Linux typically manifests itself as the
signal named SIGSEGV
, also known as a “segmentation
fault.” By default, this signal terminates the program immediately,
rather than letting the program try to recover, or reach an expected
ending point. (We commonly say in this case that the program
“crashes”). See Signals.
It is inconvenient to observe a crash by passing too large
an argument to recursive Fibonacci, because the program would run a
long time before it crashes. This algorithm is simple but
ridiculously slow: in calculating fib (n)
, the number of
(recursive) calls fib (1)
or fib (2)
that it makes equals
the final result.
However, you can observe stack overflow very quickly if you use this function instead:
int
fill_stack (int n)
{
if (n <= 1) /* This limits the depth of recursion. */
return 1;
else
return fill_stack (n - 1);
}
Under gNewSense GNU/Linux on the Lemote Yeeloong, without optimization and using the default configuration, an experiment showed there is enough stack space to do 261906 nested calls to that function. One more, and the stack overflows and the program crashes. On another platform, with a different configuration, or with a different function, the limit might be bigger or smaller.
Previous: Stack, Up: The First Example [Contents][Index]
Here’s a much faster algorithm for computing the same Fibonacci
series. It is faster for two reasons. First, it uses iteration
(that is, repetition or looping) rather than recursion, so it doesn’t
take time for a large number of function calls. But mainly, it is
faster because the number of repetitions is small—only n
.
int fib (int n) { int last = 1; /* Initial value isfib (1)
. */ int prev = 0; /* Initial value controlsfib (2)
. */ 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. */ { /* Nowlast
isfib (
andi
)prev
isfib (
. */ /* Computei
- 1)fib (
. */ int next = prev + last; /* Shift the values down. */ prev = last; last = next; /* Nowi
+ 1)last
isfib (
andi
+ 1)prev
isfib (
. But that won’t stay true for long, because we are about to incrementi
)i
. */ } return last; }
This definition computes fib (n)
in a time proportional
to n
. The comments in the definition explain how it works: it
advances through the series, always keeps the last two values in
last
and prev
, and adds them to get the next value.
Here are the additional C features that this definition uses:
Within a function, wherever a statement is called for, you can write a
block. It looks like { … }
and contains zero or
more statements and declarations. (You can also use additional
blocks as statements in a block.)
The function body also counts as a block, which is why it can contain statements and declarations.
See Blocks.
This function body contains declarations as well as statements. There
are three declarations directly in the function body, as well as a
fourth declaration in an internal block. Each starts with int
because it declares a variable whose type is integer. One declaration
can declare several variables, but each of these declarations is
simple and declares just one variable.
Variables declared inside a block (either a function body or an
internal block) are local variables. These variables exist only
within that block; their names are not defined outside the block, and
exiting the block deallocates their storage. This example declares
four local variables: last
, prev
, i
, and
next
.
The most basic local variable declaration looks like this:
type variablename;
For instance,
int i;
declares the local variable i
as an integer.
See Variable Declarations.
When you declare a variable, you can also specify its initial value, like this:
type variablename = value;
For instance,
int last = 1;
declares the local variable last
as an integer (type
int
) and starts it off with the value 1. See Initializers.
Assignment: a specific kind of expression, written with the ‘=’ operator, that stores a new value in a variable or other place. Thus,
variable = value
is an expression that computes value
and stores the value in
variable
. See Assignment Expressions.
An expression statement is an expression followed by a semicolon. That computes the value of the expression, then ignores the value.
An expression statement is useful when the expression changes some data or has other side effects—for instance, with function calls, or with assignments as in this example. See Expression Statement.
Using an expression with no side effects in an expression statement is
pointless except in very special cases. For instance, the expression
statement x;
would examine the value of x
and ignore it.
That is not useful.
The increment operator is ‘++’. ++i
is an
expression that is short for i = i + 1
.
See Increment/Decrement.
for
statementsA for
statement is a clean way of executing a statement
repeatedly—a loop (see Loop Statements). Specifically,
for (i = 1; i < n; ++i) body
means to start by doing i = 1
(set i
to one) to prepare
for the loop. The loop itself consists of
i < n
and exiting the loop if that’s false.
++i
, which increments i
).
The net result is to execute body with 1 in i
,
then with 2 in i
, and so on, stopping just before the repetition
where i
would equal n
. If n
is less than 1,
the loop will execute the body zero times.
The body of the for
statement must be one and only one
statement. You can’t write two statements in a row there; if you try
to, only the first of them will be treated as part of the loop.
The way to put multiple statements in such a place is to group them with a block, and that’s what we do in this example.
Next: Storage, Previous: The First Example, Up: Top [Contents][Index]
It’s all very well to write a Fibonacci function, but you cannot run it by itself. It is a useful program, but it is not a complete program.
In this chapter we present a complete program that contains the
fib
function. This example shows how to make the program
start, how to make it finish, how to do computation, and how to print
a result.
| • Complete Example | Turn the simple function into a full program. | |
| • Complete Explanation | Explanation of each part of the example. | |
| • Complete Line-by-Line | Explaining each line of the example. | |
| • Compile Example | Using GCC to compile the example. |
Next: Complete Explanation, Up: Complete Program [Contents][Index]
Here is the complete program that uses the simple, recursive version
of the fib
function (see Recursive Fibonacci):
#include <stdio.h>
int
fib (int n)
{
if (n <= 2) /* This avoids infinite recursion. */
return 1;
else
return fib (n - 1) + fib (n - 2);
}
int
main (void)
{
printf ("Fibonacci series item %d is %d\n",
20, fib (20));
return 0;
}
This program prints a message that shows the value of fib (20)
.
Now for an explanation of what that code means.
Next: Complete Line-by-Line, Previous: Complete Example, Up: Complete Program [Contents][Index]
Here’s the explanation of the code of the example in the previous section.
This sample program prints a message that shows the value of fib
(20)
, and exits with code 0 (which stands for successful execution).
Every C program is started by running the function named main
.
Therefore, the example program defines a function named main
to
provide a way to start it. Whatever that function does is what the
program does. See The main Function.
The main
function is the first one called when the program
runs, but it doesn’t come first in the example code. The order of the
function definitions in the source code makes no difference to the
program’s meaning.
The initial call to main
always passes certain arguments, but
main
does not have to pay attention to them. To ignore those
arguments, define main
with void
as the parameter list.
(void
as a function’s parameter list normally means “call with
no arguments,” but main
is a special case.)
The function main
returns 0 because that is
the conventional way for main
to indicate successful execution.
It could instead return a positive integer to indicate failure, and
some utility programs have specific conventions for the meaning of
certain numeric failure codes. See Values from main.
The simplest way to print text in C is by calling the printf
function, so here we explain what that does.
The first argument to printf
is a string constant
(see String Constants) that is a template for output. The
function printf
copies most of that string directly as output,
including the newline character at the end of the string, which is
written as ‘\n’. The output goes to the program’s standard
output destination, which in the usual case is the terminal.
‘%’ in the template introduces a code that substitutes other text
into the output. Specifically, ‘%d’ means to take the next
argument to printf
and substitute it into the text as a decimal
number. (The argument for ‘%d’ must be of type int
; if it
isn’t, printf
will malfunction.) So the output is a line that
looks like this:
Fibonacci series item 20 is 6765
This program does not contain a definition for printf
because
it is defined by the C library, which makes it available in all C
programs. However, each program does need to declare
printf
so it will be called correctly. The #include
line takes care of that; it includes a header file called
stdio.h into the program’s code. That file is provided by the
operating system and it contains declarations for the many standard
input/output functions in the C library, one of which is
printf
.
Don’t worry about header files for now; we’ll explain them later in Header Files.
The first argument of printf
does not have to be a string
constant; it can be any string (see Strings). However, using a
constant is the most common case.
To learn more about printf
and other facilities of the C
library, see The GNU C Library in The GNU C Library
Reference Manual.
Next: Compile Example, Previous: Complete Explanation, Up: Complete Program [Contents][Index]
Here’s the same example, explained line by line. Beginners, do you find this helpful or not? Would you prefer a different layout for the example? Please tell<EMAIL_ADDRESS>#include <stdio.h> /* Include declaration of usual */ /* I/O functions such asprintf
. */ /* Most programs need these. */ int /* This function returns anint
. */ fib (int n) /* Its name isfib
; */ /* its argument is calledn
. */ { /* Start of function body. */ /* This stops the recursion from being infinite. */ if (n <= 2) /* Ifn
is 1 or 2, */ return 1; /* makefib
return 1. */ else /* otherwise, add the two previous */ /* fibonacci numbers. */ return fib (n - 1) + fib (n - 2); } int /* This function returns anint
. */ main (void) /* Start here; ignore arguments. */ { /* Print message with numbers in it. */ printf ("Fibonacci series item %d is %d\n", 20, fib (20)); return 0; /* Terminate program, report success. */ }
Previous: Complete Line-by-Line, Up: Complete Program [Contents][Index]
To run a C program requires converting the source code into an
executable file. This is called compiling the program,
and the command to do that using GNU C is gcc
.
This example program consists of a single source file. If we call that file fib1.c, the complete command to compile it is this:
gcc -g -O -o fib1 fib1.c
Here, -g says to generate debugging information, -O says to optimize at the basic level, and -o fib1 says to put the executable program in the file fib1.
To run the program, use its file name as a shell command. For instance,
./fib1
However, unless you are sure the program is correct, you should expect to need to debug it. So use this command,
gdb fib1
which starts the GDB debugger (see A Sample GDB Session in Debugging with GDB) so you can run and
debug the executable program fib1
.
See Compilation, for an introduction to compiling more complex programs which consist of more than one source file.
Next: Beyond Integers, Previous: Complete Program, Up: Top [Contents][Index]
Storage in C programs is made up of units called bytes. On nearly all computers, a byte consists of 8 bits, but there are a few peculiar computers (mostly “embedded controllers” for very small systems) where a byte is longer than that. This manual does not try to explain the peculiarity of those computers; we assume that a byte is 8 bits.
Every C data type is made up of a certain number of bytes; that number
is the data type’s size. See Type Size, for details. The
types signed char
and unsigned char
are one byte long;
use those types to operate on data byte by byte. See Signed and Unsigned Types. You can refer to a series of consecutive bytes as an
array of char
elements; that’s what an ASCII string looks like
in memory. See String Constants.
Next: Lexical Syntax, Previous: Storage, Up: Top [Contents][Index]
So far we’ve presented programs that operate on integers. In this chapter we’ll present examples of handling non-integral numbers and arrays of numbers.
| • Float Example | A function that uses floating-point numbers. | |
| • Array Example | A function that works with arrays. | |
| • Array Example Call | How to call that function. | |
| • Array Example Variations | Different ways to write the call example. |
Next: Array Example, Up: Beyond Integers [Contents][Index]
Here’s a function that operates on and returns floating point numbers that don’t have to be integers. Floating point represents a number as a fraction together with a power of 2. (For more detail, see Floating-Point Data Types.) This example calculates the average of three floating point numbers that are passed to it as arguments:
double average_of_three (double a, double b, double c) { return (a + b + c) / 3; }
The values of the parameter a, b and c do not have to be integers, and even when they happen to be integers, most likely their average is not an integer.
double
is the usual data type in C for calculations on
floating-point numbers.
To print a double
with printf
, we must use ‘%f’
instead of ‘%d’:
printf ("Average is %f\n", average_of_three (1.1, 9.8, 3.62));
The code that calls printf
must pass a double
for
printing with ‘%f’ and an int
for printing with ‘%d’.
If the argument has the wrong type, printf
will produce garbage
output.
Here’s a complete program that computes the average of three specific numbers and prints the result:
double average_of_three (double a, double b, double c) { return (a + b + c) / 3; } int main (void) { printf ("Average is %f\n", average_of_three (1.1, 9.8, 3.62)); return 0; }
From now on we will not present examples of calls to main
.
Instead we encourage you to write them for yourself when you want
to test executing some code.
Next: Array Example Call, Previous: Float Example, Up: Beyond Integers [Contents][Index]
A function to take the average of three numbers is very specific and limited. A more general function would take the average of any number of numbers. That requires passing the numbers in an array. An array is an object in memory that contains a series of values of the same data type. This chapter presents the basic concepts and use of arrays through an example; for the full explanation, see Arrays.
Here’s a function definition to take the average of several
floating-point numbers, passed as type double
. The first
parameter, length
, specifies how many numbers are passed. The
second parameter, input_data
, is an array that holds those
numbers.
double avg_of_double (int length, double input_data[]) { double sum = 0; int i; for (i = 0; i < length; i++) sum = sum + input_data[i]; return sum / length; }
This introduces the expression to refer to an element of an array:
input_data[i]
means the element at index i
in
input_data
. The index of the element can be any expression
with an integer value; in this case, the expression is i
.
See Accessing Array Elements.
The lowest valid index in an array is 0, not 1, and the highest valid index is one less than the number of elements. (This is known as zero-origin indexing.)
This example also introduces the way to declare that a function
parameter is an array. Such declarations are modeled after the syntax
for an element of the array. Just as double foo
declares that
foo
is of type double
, double input_data[]
declares that each element of input_data
is of type
double
. Therefore, input_data
itself has type “array
of double
.”
When declaring an array parameter, it’s not necessary to say how long
the array is. In this case, the parameter input_data
has no
length information. That’s why the function needs another parameter,
length
, for the caller to provide that information to the
function avg_of_double
.
Next: Array Example Variations, Previous: Array Example, Up: Beyond Integers [Contents][Index]
To call the function avg_of_double
requires making an
array and then passing it as an argument. Here is an example.
{ /* The array of values to average. */ double nums_to_average[5]; /* The average, once we compute it. */ double average; /* Fill in elements ofnums_to_average
. */ nums_to_average[0] = 58.7; nums_to_average[1] = 5.1; nums_to_average[2] = 7.7; nums_to_average[3] = 105.2; nums_to_average[4] = -3.14159; average = avg_of_double (5, nums_to_average); /* …now make use ofaverage
… */ }
This shows an array subscripting expression again, this time on the left side of an assignment, storing a value into an element of an array.
It also shows how to declare a local variable that is an array:
double nums_to_average[5];
. Since this declaration allocates the
space for the array, it needs to know the array’s length. You can
specify the length with any expression whose value is an integer, but
in this declaration the length is a constant, the integer 5.
The name of the array, when used by itself as an expression, stands
for the address of the array’s data, and that’s what gets passed to
the function avg_of_double
in avg_of_double (5,
nums_to_average)
.
We can make the code easier to maintain by avoiding the need to write
5, the array length, when calling avg_of_double
. That way, if
we change the array to include more elements, we won’t have to change
that call. One way to do this is with the sizeof
operator:
average = avg_of_double ((sizeof (nums_to_average) / sizeof (nums_to_average[0])), nums_to_average);
This computes the number of elements in nums_to_average
by dividing
its total size by the size of one element. See Type Size, for more
details of using sizeof
.
We don’t show in this example what happens after storing the result of
avg_of_double
in the variable average
. Presumably
more code would follow that uses that result somehow. (Why compute
the average and not use it?) But that isn’t part of this topic.
Previous: Array Example Call, Up: Beyond Integers [Contents][Index]
The code to call avg_of_double
has two declarations that
start with the same data type:
/* The array of values to average. */ double nums_to_average[5]; /* The average, once we compute it. */ double average;
In C, you can combine the two, like this:
double nums_to_average[5], average;
This declares nums_to_average
so each of its elements is a
double
, and average
so that it simply is a
double
.
However, while you can combine them, that doesn’t mean you should. If it is useful to write comments about the variables, and usually it is, then it’s clearer to keep the declarations separate so you can put a comment on each one.
We set all of the elements of the array nums_to_average
with
assignments, but it is more convenient to use an initializer in the
declaration:
{
/* The array of values to average. */
double nums_to_average[]
= { 58.7, 5.1, 7.7, 105.2, -3.14159 };
/* The average, once we compute it. */
average = avg_of_double ((sizeof (nums_to_average)
/ sizeof (nums_to_average[0])),
nums_to_average);
/* …now make use of average
… */
}
The array initializer is a comma-separated list of values, delimited by braces. See Initializers.
Note that the declaration does not specify a size for
nums_to_average
, so the size is determined from the
initializer. There are five values in the initializer, so
nums_to_average
gets length 5. If we add another element to
the initializer, nums_to_average
will have six elements.
Because the code computes the number of elements from the size of
the array, using sizeof
, the program will operate on all the
elements in the initializer, regardless of how many those are.
Next: Arithmetic, Previous: Beyond Integers, Up: Top [Contents][Index]
To start the full description of the C language, we explain the lexical syntax and lexical units of C code. The lexical units of a programming language are known as tokens. This chapter covers all the tokens of C except for constants, which are covered in a later chapter (see Constants). One vital kind of token is the identifier (see Identifiers), which is used for names of any kind.
| • English | Write programs in English! | |
| • Characters | The characters allowed in C programs. | |
| • Whitespace | The particulars of whitespace characters. | |
| • Comments | How to include comments in C code. | |
| • Identifiers | How to form identifiers (names). | |
| • Operators/Punctuation | Characters used as operators or punctuation. | |
| • Line Continuation | Splitting one line into multiple lines. |
Next: Characters, Up: Lexical Syntax [Contents][Index]
In principle, you can write the function and variable names in a program, and the comments, in any human language. C allows any kinds of characters in comments, and you can put non-ASCII characters into identifiers with a special prefix. However, to enable programmers in all countries to understand and develop the program, it is best given today’s circumstances to write identifiers and comments in English.
English is the one language that programmers in all countries generally study. If a program’s names are in English, most programmers in Bangladesh, Belgium, Bolivia, Brazil, and Bulgaria can understand them. Most programmers in those countries can speak English, or at least read it, but they do not read each other’s languages at all. In India, with so many languages, two programmers may have no common language other than English.
If you don’t feel confident in writing English, do the best you can, and follow each English comment with a version in a language you write better; add a note asking others to translate that to English. Someone will eventually do that.
The program’s user interface is a different matter. We don’t need to
choose one language for that; it is easy to support multiple languages
and let each user choose the language to use. This requires writing
the program to support localization of its interface. (The
gettext
package exists to support this; see The GNU C Library in The GNU C Library Reference
Manual.) Then a community-based translation effort can provide
support for all the languages users want to use.
Next: Whitespace, Previous: English, Up: Lexical Syntax [Contents][Index]
GNU C source files are usually written in the ASCII character set, which was defined in the 1960s for English. However, they can also include Unicode characters represented in the UTF-8 multibyte encoding. This makes it possible to represent accented letters such as ‘á’, as well as other scripts such as Arabic, Chinese, Cyrillic, Hebrew, Japanese, and Korean.1
In C source code, non-ASCII characters are valid in comments, in wide character constants (see Wide Character Constants), and in string constants (see String Constants).
Another way to specify non-ASCII characters in constants (character or string) and identifiers is with an escape sequence starting with backslash, specifying the intended Unicode character. (See Unicode Character Codes.) This specifies non-ASCII characters without putting a real non-ASCII character in the source file itself.
C accepts two-character aliases called digraphs for certain characters. See Digraphs.
Next: Comments, Previous: Characters, Up: Lexical Syntax [Contents][Index]
Whitespace means characters that exist in a file but appear blank in a printed listing of a file (or traditionally did appear blank, several decades ago). The C language requires whitespace in order to separate two consecutive identifiers, or to separate an identifier from a numeric constant. Other than that, and a few special situations described later, whitespace is optional; you can put it in when you wish, to make the code easier to read.
Space and tab in C code are treated as whitespace characters. So are line breaks. You can represent a line break with the newline character (also called linefeed or LF), CR (carriage return), or the CRLF sequence (two characters: carriage return followed by a newline character).
The formfeed character, Control-L, was traditionally used to divide a file into pages. It is still used this way in source code, and the tools that generate nice printouts of source code still start a new page after each “formfeed” character. Dividing code into pages separated by formfeed characters is a good way to break it up into comprehensible pieces and show other programmers where they start and end.
The vertical tab character, Control-K, was traditionally used to make printing advance down to the next section of a page. We know of no particular reason to use it in source code, but it is still accepted as whitespace in C.
Comments are also syntactically equivalent to whitespace.
Next: Identifiers, Previous: Whitespace, Up: Lexical Syntax [Contents][Index]
A comment encapsulates text that has no effect on the program’s execution or meaning.
The purpose of comments is to explain the code to people that read it. Writing good comments for your code is tremendously important—they should provide background information that helps programmers understand the reasons why the code is written the way it is. You, returning to the code six months from now, will need the help of these comments to remember why you wrote it this way.
Outdated comments that become incorrect are counterproductive, so part of the software developer’s responsibility is to update comments as needed to correspond with changes to the program code.
C allows two kinds of comment syntax, the traditional style and the C++ style. A traditional C comment starts with ‘/*’ and ends with ‘*/’. For instance,
/* This is a comment in traditional C syntax. */
A traditional comment can contain ‘/*’, but these delimiters do not nest as pairs. The first ‘*/’ ends the comment regardless of whether it contains ‘/*’ sequences.
/* This /* is a comment */ But this is not! */
A line comment starts with ‘//’ and ends at the end of the line. For instance,
// This is a comment in C++ style.
Line comments do nest, in effect, because ‘//’ inside a line comment is part of that comment:
// this whole line is // one comment This is code, not comment.
It is safe to put line comments inside block comments, or vice versa.
/* traditional comment // contains line comment more traditional comment */ text here is not a comment // line comment /* contains traditional comment */
But beware of commenting out one end of a traditional comment with a line comment. The delimiter ‘/*’ doesn’t start a comment if it occurs inside an already-started comment.
// line comment /* That would ordinarily begin a block comment. Oops! The line comment has ended; this isn't a comment any more. */
Comments are not recognized within string constants. "/* blah */" is the string constant ‘/* blah */’, not an empty string.
In this manual we show the text in comments in a variable-width font, for readability, but this font distinction does not exist in source files.
A comment is syntactically equivalent to whitespace, so it always separates tokens. Thus,
int/* comment */foo; is equivalent to int foo;
but clean code always uses real whitespace to separate the comment visually from surrounding code.
Next: Operators/Punctuation, Previous: Comments, Up: Lexical Syntax [Contents][Index]
An identifier (name) in C is a sequence of letters and digits, as well as ‘_’, that does not start with a digit. Most compilers also allow ‘$’. An identifier can be as long as you like; for example,
int anti_dis_establishment_arian_ism;
Letters in identifiers are case-sensitive in C; thus, a
and A
are two different identifiers.
Identifiers in C are used as variable names, function names, typedef
names, enumeration constants, type tags, field names, and labels.
Certain identifiers in C are keywords, which means they have
specific syntactic meanings. Keywords in C are reserved words,
meaning you cannot use them in any other way. For instance, you can’t
define a variable or function named return
or if
.
You can also include other characters, even non-ASCII characters, in identifiers by writing their Unicode character names, which start with ‘\u’ or ‘\U’, in the identifier name. See Unicode Character Codes. However, it is usually a bad idea to use non-ASCII characters in identifiers, and when they are written in English, they never need non-ASCII characters. See English.
Whitespace is required to separate two consecutive identifiers, or to separate an identifier from a preceding or following numeric constant.
Next: Line Continuation, Previous: Identifiers, Up: Lexical Syntax [Contents][Index]
Here we describe the lexical syntax of operators and punctuation in C. The specific operators of C and their meanings are presented in subsequent chapters.
Most operators in C consist of one or two characters that can’t be used in identifiers. The characters used for operators in C are ‘!~^&|*/%+-=<>,.?:’.
 For instance, ‘-’ is the operator for negation (with one operand) and the operator for subtraction (with two operands).
Some operators are two characters. For example, ‘++’ is the increment operator. Recognition of multicharacter operators works by grouping together as many consecutive characters as can constitute one operator.
For instance, the character sequence ‘++’ is always interpreted
as the increment operator; therefore, if we want to write two
consecutive instances of the operator ‘+’, we must separate them
with a space so that they do not combine as one token. Applying the
same rule, a+++++b
is always tokenized as a++ ++ + b
, not as a++ + ++b
, even though the latter could be part
of a valid C program and the former could not (since a++
is not an lvalue and thus can’t be the operand of ++
).
A few C operators are keywords rather than special characters. They
include sizeof
(see Type Size) and _Alignof
(see Type Alignment).
The characters ‘;{}[]()’ are used for punctuation and grouping. Semicolon (‘;’) ends a statement. Braces (‘{’ and ‘}’) begin and end a block at the statement level (see Blocks), and surround the initializer (see Initializers) for a variable with multiple elements or components (such as arrays or structures).
Square brackets (‘[’ and ‘]’) do array indexing, as in
array[5]
.
Parentheses are used in expressions for explicit nesting of
expressions (see Basic Arithmetic), around the parameter
declarations in a function declaration or definition, and around the
arguments in a function call, as in printf ("Foo %d\n", i)
(see Function Calls). Several kinds of statements also use
parentheses as part of their syntax—for instance, if
statements, for
statements, while
statements, and
switch
statements. See if Statement, and following
sections.
Parentheses are also required around the operand of the operator
keywords sizeof
and _Alignof
when the operand is a data
type rather than a value. See Type Size.
Previous: Operators/Punctuation, Up: Lexical Syntax [Contents][Index]
The sequence of a backslash and a newline is ignored absolutely anywhere in a C program. This makes it possible to split a single source line into multiple lines in the source file. GNU C tolerates and ignores other whitespace between the backslash and the newline. In particular, it always ignores a CR (carriage return) character there, in case some text editor decided to end the line with the CRLF sequence.
The main use of line continuation in C is for macro definitions that would be inconveniently long for a single line (see Macros).
It is possible to continue a line comment onto another line with backslash-newline. You can put backslash-newline in the middle of an identifier, even a keyword, or an operator. You can even split ‘/*’, ‘*/’, and ‘//’ onto multiple lines with backslash-newline.
Don’t do those things in real programs, since they make code hard to read.
Note: For the sake of using certain tools on the source code, it is wise to end every source file with a newline character which is not preceded by a backslash, so that it really ends the last line.
Next: Assignment Expressions, Previous: Lexical Syntax, Up: Top [Contents][Index]
Arithmetic operators in C attempt to be as similar as possible to the abstract arithmetic operations, but it is impossible to do this perfectly. Numbers in a computer have a finite range of possible values, and non-integer values have a limit on their possible accuracy. Nonetheless, in most cases you will encounter no surprises in using ‘+’ for addition, ‘-’ for subtraction, and ‘*’ for multiplication.
Each C operator has a precedence, which is its rank in the grammatical order of the various operators. The operators with the highest precedence grab adjoining operands first; these expressions then become operands for operators of lower precedence. We give some information about precedence of operators in this chapter where we describe the operators; for the full explanation, see Binary Operator Grammar.
The arithmetic operators always promote their operands before operating on them. This means converting narrow integer data types to a wider data type (see Operand Promotions). If you are just learning C, don’t worry about this yet.
Given two operands that have different types, most arithmetic
operations convert them both to their common type. For
instance, if one is int
and the other is double
, the
common type is double
. (That’s because double
can
represent all the values that an int
can hold, but not vice
versa.) For the full details, see Common Type.
| • Basic Arithmetic | Addition, subtraction, multiplication, and division. | |
| • Integer Arithmetic | How C performs arithmetic with integer values. | |
| • Integer Overflow | When an integer value exceeds the range of its type. | |
| • Mixed Mode | Calculating with both integer values and floating-point values. | |
| • Division and Remainder | How integer division works. | |
| • Numeric Comparisons | Comparing numeric values for equality or order. | |
| • Shift Operations | Shift integer bits left or right. | |
| • Bitwise Operations | Bitwise conjunction, disjunction, negation. |
Next: Integer Arithmetic, Up: Arithmetic [Contents][Index]
Basic arithmetic in C is done with the usual binary operators of
algebra: addition (‘+’), subtraction (‘-’), multiplication
(‘*’) and division (‘/’). The unary operator ‘-’ is
used to change the sign of a number. The unary +
operator also
exists; it yields its operand unaltered.
‘/’ is the division operator, but dividing integers may not give the result you expect. Its value is an integer, which is not equal to the mathematical quotient when that is a fraction. Use ‘%’ to get the corresponding integer remainder when necessary. See Division and Remainder. Floating point division yields value as close as possible to the mathematical quotient.
These operators use algebraic syntax with the usual algebraic precedence rule (see Binary Operator Grammar) that multiplication and division are done before addition and subtraction, but you can use parentheses to explicitly specify how the operators nest. They are left-associative (see Associativity and Ordering). Thus,
-a + b - c + d * e / f
is equivalent to
(((-a) + b) - c) + ((d * e) / f)
Next: Integer Overflow, Previous: Basic Arithmetic, Up: Arithmetic [Contents][Index]
Each of the basic arithmetic operations in C has two variants for integers: signed and unsigned. The choice is determined by the data types of their operands.
Each integer data type in C is either signed or unsigned. A signed type can hold a range of positive and negative numbers, with zero near the middle of the range. An unsigned type can hold only nonnegative numbers; its range starts with zero and runs upward.
The most basic integer types are int
, which normally can hold
numbers from -2,147,483,648 to 2,147,483,647, and unsigned
int
, which normally can hold numbers from 0 to 4,294.967,295. (This
assumes int
is 32 bits wide, always true for GNU C on real
computers but not always on embedded controllers.) See Integer Types, for full information about integer types.
When a basic arithmetic operation is given two signed operands, it does signed arithmetic. Given two unsigned operands, it does unsigned arithmetic.
If one operand is unsigned int
and the other is int
, the
operator treats them both as unsigned. More generally, the common
type of the operands determines whether the operation is signed or
not. See Common Type.
Printing the results of unsigned arithmetic with printf
using
‘%d’ can produce surprising results for values far away from
zero. Even though the rules above say that the computation was done
with unsigned arithmetic, the printed result may appear to be signed!
The explanation is that the bit pattern resulting from addition, subtraction or multiplication is actually the same for signed and unsigned operations. The difference is only in the data type of the result, which affects the interpretation of the result bit pattern, and whether the arithmetic operation can overflow (see the next section).
But ‘%d’ doesn’t know its argument’s data type. It sees only the
value’s bit pattern, and it is defined to interpret that as
signed int
. To print it as unsigned requires using ‘%u’
instead of ‘%d’. See The GNU C Library in The GNU C Library Reference Manual.
Arithmetic in C never operates directly on narrow integer types (those
with fewer bits than int
; Narrow Integers). Instead it
“promotes” them to int
. See Operand Promotions.
Next: Mixed Mode, Previous: Integer Arithmetic, Up: Arithmetic [Contents][Index]
When the mathematical value of an arithmetic operation doesn’t fit in the range of the data type in use, that’s called overflow. When it happens in integer arithmetic, it is integer overflow.
Integer overflow happens only in arithmetic operations. Type conversion operations, by definition, do not cause overflow, not even when the result can’t fit in its new type. See Integer Conversion.
Signed numbers use two’s-complement representation, in which the most negative number lacks a positive counterpart (see Integers in Depth). Thus, the unary ‘-’ operator on a signed integer can overflow.
| • Unsigned Overflow | Overlow in unsigned integer arithmetic. | |
| • Signed Overflow | Overlow in signed integer arithmetic. |
Next: Signed Overflow, Up: Integer Overflow [Contents][Index]
Unsigned arithmetic in C ignores overflow; it produces the true result modulo the nth power of 2, where n is the number of bits in the data type. We say it “truncates” the true result to the lowest n bits.
A true result that is negative, when taken modulo the nth power of 2, yields a positive number. For instance,
unsigned int x = 1; unsigned int y; y = -x;
causes overflow because the negative number -1 can’t be stored
in an unsigned type. The actual result, which is -1 modulo the
nth power of 2, is one less than the nth power of 2. That
is the largest value that the unsigned data type can store. For a
32-bit unsigned int
, the value is 4,294,967,295. See Maximum and Minimum Values.
Adding that number to itself, as here,
unsigned int z; z = y + y;
ought to yield 8,489,934,590; however, that is again too large to fit, so overflow truncates the value to 4,294,967,294. If that were a signed integer, it would mean -2, which (not by coincidence) equals -1 + -1.
Previous: Unsigned Overflow, Up: Integer Overflow [Contents][Index]
For signed integers, the result of overflow in C is in principle undefined, meaning that anything whatsoever could happen. Therefore, C compilers can do optimizations that treat the overflow case with total unconcern. (Since the result of overflow is undefined in principle, one cannot claim that these optimizations are erroneous.)
Watch out: These optimizations can do surprising things. For instance,
int i;
…
if (i < i + 1)
x = 5;
could be optimized to do the assignment unconditionally, because the
if
-condition is always true if i + 1
does not overflow.
GCC offers compiler options to control handling signed integer overflow. These options operate per module; that is, each module behaves according to the options it was compiled with.
These two options specify particular ways to handle signed integer overflow, other than the default way:
Make signed integer operations well-defined, like unsigned integer operations: they produce the n low-order bits of the true result. The highest of those n bits is the sign bit of the result. With -fwrapv, these out-of-range operations are not considered overflow, so (strictly speaking) integer overflow never happens.
The option -fwrapv enables some optimizations based on the defined values of out-of-range results. In GCC 8, it disables optimizations that are based on assuming signed integer operations will not overflow.
Generate a signal SIGFPE
when signed integer overflow occurs.
This terminates the program unless the program handles the signal.
See Signals.
One other option is useful for finding where overflow occurs:
Output a warning message at run time when signed integer overflow occurs. This checks the ‘+’, ‘*’, and ‘-’ operators. This takes priority over -ftrapv.
Next: Division and Remainder, Previous: Integer Overflow, Up: Arithmetic [Contents][Index]
Mixing integers and floating-point numbers in a basic arithmetic operation converts the integers automatically to floating point. In most cases, this gives exactly the desired results. But sometimes it matters precisely where the conversion occurs.
If i
and j
are integers, (i + j) * 2.0
adds them
as an integer, then converts the sum to floating point for the
multiplication. If the addition gets an overflow, that is not
equivalent to converting both integers to floating point and then
adding them. You can get the latter result by explicitly converting
the integers, as in ((double) i + (double) j) * 2.0
.
See Explicit Type Conversion.
Adding or multiplying several values, including some integers and some
floating point, does the operations left to right. Thus, 3.0 +
i + j
converts i
to floating point, then adds 3.0, then
converts j
to floating point and adds that. You can specify a
different order using parentheses: 3.0 + (i + j)
adds i
and j
first and then adds that result (converting to floating
point) to 3.0. In this respect, C differs from other languages, such
as Fortran.
Next: Numeric Comparisons, Previous: Mixed Mode, Up: Arithmetic [Contents][Index]
Division of integers in C rounds the result to an integer. The result is always rounded towards zero.
16 / 3 ⇒ 5 -16 / 3 ⇒ -5 16 / -3 ⇒ -5 -16 / -3 ⇒ 5
To get the corresponding remainder, use the ‘%’ operator:
16 % 3 ⇒ 1 -16 % 3 ⇒ -1 16 % -3 ⇒ 1 -16 % -3 ⇒ -1
‘%’ has the same operator precedence as ‘/’ and ‘*’.
From the rounded quotient and the remainder, you can reconstruct the dividend, like this:
int original_dividend (int divisor, int quotient, int remainder) { return divisor * quotient + remainder; }
To do unrounded division, use floating point. If only one operand is floating point, ‘/’ converts the other operand to floating point.
16.0 / 3 ⇒ 5.333333333333333 16 / 3.0 ⇒ 5.333333333333333 16.0 / 3.0 ⇒ 5.333333333333333 16 / 3 ⇒ 5
The remainder operator ‘%’ is not allowed for floating-point operands, because it is not needed. The concept of remainder makes sense for integers because the result of division of integers has to be an integer. For floating point, the result of division is a floating-point number, in other words a fraction, which will differ from the exact result only by a very small amount.
There are functions in the standard C library to calculate remainders from integral-values division of floating-point numbers. See The GNU C Library in The GNU C Library Reference Manual.
Integer division overflows in one specific case: dividing the smallest
negative value for the data type (see Maximum and Minimum Values)
by -1. That’s because the correct result, which is the
corresponding positive number, does not fit (see Integer Overflow)
in the same number of bits. On some computers now in use, this always
causes a signal SIGFPE
(see Signals), the same behavior
that the option -ftrapv specifies (see Signed Overflow).
Division by zero leads to unpredictable results—depending on the
type of computer, it might cause a signal SIGFPE
, or it might
produce a numeric result.
Watch out: Make sure the program does not divide by zero. If you can’t prove that the divisor is not zero, test whether it is zero, and skip the division if so.
Next: Shift Operations, Previous: Division and Remainder, Up: Arithmetic [Contents][Index]
There are two kinds of comparison operators: equality and ordering. Equality comparisons test whether two expressions have the same value. The result is a truth value: a number that is 1 for “true” and 0 for “false.”
a == b /* Test for equal. */ a != b /* Test for not equal. */
The equality comparison is written ==
because plain =
is the assignment operator.
Ordering comparisons test which operand is greater or less. Their results are truth values. These are the ordering comparisons of C:
a < b /* Test for less-than. */ a > b /* Test for greater-than. */ a <= b /* Test for less-than-or-equal. */ a >= b /* Test for greater-than-or-equal. */
For any integers a
and b
, exactly one of the comparisons
a < b
, a == b
and a > b
is true, just as in
mathematics. However, if a
and b
are special floating
point values (not ordinary numbers), all three can be false.
See Special Float Values, and Invalid Optimizations.
Next: Bitwise Operations, Previous: Numeric Comparisons, Up: Arithmetic [Contents][Index]
Shifting an integer means moving the bit values to the left or right within the bits of the data type. Shifting is defined only for integers. Here’s the way to write it:
/* Left shift. */ 5 << 2 ⇒ 20 /* Right shift. */ 5 >> 2 ⇒ 1
The left operand is the value to be shifted, and the right operand
says how many bits to shift it (the shift count). The left
operand is promoted (see Operand Promotions), so shifting never
operates on a narrow integer type; it’s always either int
or
wider. The value of the shift operator has the same type as the
promoted left operand.
| • Bits Shifted In | How shifting makes new bits to shift in. | |
| • Shift Caveats | Caveats of shift operations. | |
| • Shift Hacks | Clever tricks with shift operations. |
Next: Shift Caveats, Up: Shift Operations [Contents][Index]
A shift operation shifts towards one end of the number and has to generate new bits at the other end.
Shifting left one bit must generate a new least significant bit. It always brings in zero there. It is equivalent to multiplying by the appropriate power of 2. For example,
5 << 3 is equivalent to 5 * 2*2*2 -10 << 4 is equivalent to -10 * 2*2*2*2
The meaning of shifting right depends on whether the data type is signed or unsigned (see Signed and Unsigned Types). For a signed data type, it performs “arithmetic shift,” which keeps the number’s sign unchanged by duplicating the sign bit. For an unsigned data type, it performs “logical shift,” which always shifts in zeros at the most significant bit.
In both cases, shifting right one bit is division by two, rounding towards negative infinity. For example,
(unsigned) 19 >> 2 ⇒ 4 (unsigned) 20 >> 2 ⇒ 5 (unsigned) 21 >> 2 ⇒ 5
For negative left operand a
, a >> 1
is not equivalent to
a / 2
. They both divide by 2, but ‘/’ rounds toward
zero.
The shift count must be zero or greater. Shifting by a negative number of bits gives machine-dependent results.
Next: Shift Hacks, Previous: Bits Shifted In, Up: Shift Operations [Contents][Index]
Warning: If the shift count is greater than or equal to the width in bits of the first operand, the results are machine-dependent. Logically speaking, the “correct” value would be either -1 (for right shift of a negative number) or 0 (in all other cases), but what it really generates is whatever the machine’s shift instruction does in that case. So unless you can prove that the second operand is not too large, write code to check it at run time.
Warning: Never rely on how the shift operators relate in precedence to other arithmetic binary operators. Programmers don’t remember these precedences, and won’t understand the code. Always use parentheses to explicitly specify the nesting, like this:
a + (b << 5) /* Shift first, then add. */ (a + b) << 5 /* Add first, then shift. */
Note: according to the C standard, shifting of signed values isn’t guaranteed to work properly when the value shifted is negative, or becomes negative during the operation of shifting left. However, only pedants have a reason to be concerned about this; only computers with strange shift instructions could plausibly do this wrong. In GNU C, the operation always works as expected,
Previous: Shift Caveats, Up: Shift Operations [Contents][Index]
You can use the shift operators for various useful hacks. For
example, given a date specified by day of the month d
, month
m
, and year y
, you can store the entire date in a single
integer date
:
unsigned int d = 12; unsigned int m = 6; unsigned int y = 1983; unsigned int date = ((y << 4) + m) << 5) + d;
To extract the original day, month, and year out of
date
, use a combination of shift and remainder.
d = date % 32; m = (date >> 5) % 16; y = date >> 9;
-1 << LOWBITS
is a clever way to make an integer whose
LOWBITS
lowest bits are all 0 and the rest are all 1.
-(1 << LOWBITS)
is equivalent to that, due to associativity of
multiplication, since negating a value is equivalent to multiplying it
by -1.
Previous: Shift Operations, Up: Arithmetic [Contents][Index]
Bitwise operators operate on integers, treating each bit independently. They are not allowed for floating-point types.
The examples in this section use binary constants, starting with
‘0b’ (see Integer Constants). They stand for 32-bit integers
of type int
.
~a
Unary operator for bitwise negation; this changes each bit of
a
from 1 to 0 or from 0 to 1.
~0b10101000 ⇒ 0b11111111111111111111111101010111 ~0 ⇒ 0b11111111111111111111111111111111 ~0b11111111111111111111111111111111 ⇒ 0 ~ (-1) ⇒ 0
It is useful to remember that ~x + 1
equals
-x
, for integers, and ~x
equals
-x - 1
. The last example above shows this with -1
as x.
a
& b
Binary operator for bitwise “and” or “conjunction.” Each bit in
the result is 1 if that bit is 1 in both a
and b
.
0b10101010 & 0b11001100 ⇒ 0b10001000
a
| b
Binary operator for bitwise “or” (“inclusive or” or
“disjunction”). Each bit in the result is 1 if that bit is 1 in
either a
or b
.
0b10101010 | 0b11001100 ⇒ 0b11101110
a
^ b
Binary operator for bitwise “xor” (“exclusive or”). Each bit in
the result is 1 if that bit is 1 in exactly one of a
and b
.
0b10101010 ^ 0b11001100 ⇒ 0b01100110
To understand the effect of these operators on signed integers, keep
in mind that all modern computers use two’s-complement representation
(see Integer Representations) for negative integers. This means
that the highest bit of the number indicates the sign; it is 1 for a
negative number and 0 for a positive number. In a negative number,
the value in the other bits increases as the number gets closer
to zero, so that 0b111…111
is -1 and
0b100…000
is the most negative possible integer.
Warning: C defines a precedence ordering for the bitwise binary operators, but you should never rely on it. You should never rely on how bitwise binary operators relate in precedence to the arithmetic and shift binary operators. Other programmers don’t remember this precedence ordering, so always use parentheses to explicitly specify the nesting.
For example, suppose offset
is an integer that specifies
the offset within shared memory of a table, except that its bottom few
bits (LOWBITS
says how many) are special flags. Here’s
how to get just that offset and add it to the base address.
shared_mem_base + (offset & (-1 << LOWBITS))
Thanks to the outer set of parentheses, we don’t need to know whether ‘&’ has higher precedence than ‘+’. Thanks to the inner set, we don’t need to know whether ‘&’ has higher precedence than ‘<<’. But we can rely on all unary operators to have higher precedence than any binary operator, so we don’t need parentheses around the left operand of ‘<<’.
Next: Execution Control Expressions, Previous: Arithmetic, Up: Top [Contents][Index]
As a general concept in programming, an assignment is a construct that stores a new value into a place where values can be stored—for instance, in a variable. Such places are called lvalues (see Lvalues) because they are locations that hold a value.
An assignment in C is an expression because it has a value; we call it an assignment expression. A simple assignment looks like
lvalue = value-to-store
We say it assigns the value of the expression value-to-store to the location lvalue, or that it stores value-to-store there. You can think of the “l” in “lvalue” as standing for “left,” since that’s what you put on the left side of the assignment operator.
However, that’s not the only way to use an lvalue, and not all lvalues
can be assigned to. To use the lvalue in the left side of an
assignment, it has to be modifiable. In C, that means it was
not declared with the type qualifier const
(see const).
The value of the assignment expression is that of lvalue after the new value is stored in it. This means you can use an assignment inside other expressions. Assignment operators are right-associative so that
x = y = z = 0;
is equivalent to
x = (y = (z = 0));
This is the only useful way for them to associate; the other way,
((x = y) = z) = 0;
would be invalid since an assignment expression such as x = y
is not valid as an lvalue.
Warning: Write parentheses around an assignment if you nest it inside another expression, unless that is a conditional expression, or comma-separated series, or another assignment.
| • Simple Assignment | The basics of storing a value. | |
| • Lvalues | Expressions into which a value can be stored. | |
| • Modifying Assignment | Shorthand for changing an lvalue’s contents. | |
| • Increment/Decrement | Shorthand for incrementing and decrementing an lvalue’s contents. | |
| • Postincrement/Postdecrement | Accessing then incrementing or decrementing. | |
| • Assignment in Subexpressions | How to avoid ambiguity. | |
| • Write Assignments Separately | Write assignments as separate statements. |
Next: Lvalues, Up: Assignment Expressions [Contents][Index]
A simple assignment expression computes the value of the right
operand and stores it into the lvalue on the left. Here is a simple
assignment expression that stores 5 in i
:
i = 5
We say that this is an assignment to the variable i
and
that it assigns i
the value 5. It has no semicolon
because it is an expression (so it has a value). Adding a semicolon
at the end would make it a statement (see Expression Statement).
Here is another example of a simple assignment expression. Its operands are not simple, but the kind of assignment done here is simple assignment.
x[foo ()] = y + 6
A simple assignment with two different numeric data types converts the right operand value to the lvalue’s type, if possible. It can convert any numeric type to any other numeric type.
Simple assignment is also allowed on some non-numeric types: pointers (see Pointers), structures (see Structure Assignment), and unions (see Unions).
Warning: Assignment is not allowed on arrays because there are no array values in C; C variables can be arrays, but these arrays cannot be manipulated as wholes. See Limitations of C Arrays.
See Assignment Type Conversions, for the complete rules about data types used in assignments.
Next: Modifying Assignment, Previous: Simple Assignment, Up: Assignment Expressions [Contents][Index]
An expression that identifies a memory space that holds a value is called an lvalue, because it is a location that can hold a value.
The standard kinds of lvalues are:
If an expression’s outermost operation is any other operator, that
expression is not an lvalue. Thus, the variable x
is an
lvalue, but x + 0
is not, even though these two expressions
compute the same value (assuming x
is a number).
An array can be an lvalue (the rules above determine whether it is
one), but using the array in an expression converts it automatically
to a pointer to the first element. The result of this conversion is
not an lvalue. Thus, if the variable a
is an array, you can’t
use a
by itself as the left operand of an assignment. But you
can assign to an element of a
, such as a[0]
. That is an
lvalue since a
is an lvalue.
Next: Increment/Decrement, Previous: Lvalues, Up: Assignment Expressions [Contents][Index]
You can abbreviate the common construct
lvalue = lvalue + expression
as
lvalue += expression
This is known as a modifying assignment. For instance,
i = i + 5; i += 5;
shows two statements that are equivalent. The first uses simple assignment; the second uses modifying assignment.
Modifying assignment works with any binary arithmetic operator. For instance, you can subtract something from an lvalue like this,
lvalue -= expression
or multiply it by a certain amount like this,
lvalue *= expression
or shift it by a certain amount like this.
lvalue <<= expression lvalue >>= expression
In most cases, this feature adds no power to the language, but it provides substantial convenience. Also, when lvalue contains code that has side effects, the simple assignment performs those side effects twice, while the modifying assignment performs them once. For instance,
x[foo ()] = x[foo ()] + 5;
calls foo
twice, and it could return different values each
time. If foo ()
returns 1 the first time and 3 the second
time, then the effect could be to add x[3]
and 5 and store the
result in x[1]
, or to add x[1]
and 5 and store the
result in x[3]
. We don’t know which of the two it will do,
because C does not specify which call to foo
is computed first.
Such a statement is not well defined, and shouldn’t be used.
By contrast,
x[foo ()] += 5;
is well defined: it calls foo
only once to determine which
element of x
to adjust, and it adjusts that element by adding 5
to it.
Next: Postincrement/Postdecrement, Previous: Modifying Assignment, Up: Assignment Expressions [Contents][Index]
The operators ‘++’ and ‘--’ are the increment and decrement operators. When used on a numeric value, they add or subtract 1. We don’t consider them assignments, but they are equivalent to assignments.
Using ‘++’ or ‘--’ as a prefix, before an lvalue, is called preincrement or predecrement. This adds or subtracts 1 and the result becomes the expression’s value. For instance,
#include <stdio.h> /* Declares printf
. */
int
main (void)
{
int i = 5;
printf ("%d\n", i);
printf ("%d\n", ++i);
printf ("%d\n", i);
return 0;
}
prints lines containing 5, 6, and 6 again. The expression ++i
increments i
from 5 to 6, and has the value 6, so the output
from printf
on that line says ‘6’.
Using ‘--’ instead, for predecrement,
#include <stdio.h> /* Declares printf
. */
int
main (void)
{
int i = 5;
printf ("%d\n", i);
printf ("%d\n", --i);
printf ("%d\n", i);
return 0;
}
prints three lines that contain (respectively) ‘5’, ‘4’, and again ‘4’.
Next: Assignment in Subexpressions, Previous: Increment/Decrement, Up: Assignment Expressions [Contents][Index]
Using ‘++’ or ‘--’ after an lvalue does something
peculiar: it gets the value directly out of the lvalue and then
increments or decrement it. Thus, the value of i++
is the same
as the value of i
, but i++
also increments i
“a
little later.” This is called postincrement or
postdecrement.
For example,
#include <stdio.h> /* Declares printf
. */
int
main (void)
{
int i = 5;
printf ("%d\n", i);
printf ("%d\n", i++);
printf ("%d\n", i);
return 0;
}
prints lines containing 5, again 5, and 6. The expression i++
has the value 5, which is the value of i
at the time,
but it increments i
from 5 to 6 just a little later.
How much later is “just a little later”? That is flexible. The increment has to happen by the next sequence point. In simple cases, that means by the end of the statement. See Sequence Points.
If a unary operator precedes a postincrement or postincrement expression, the increment nests inside:
-a++ is equivalent to -(a++)
That’s the only order that makes sense; -a
is not an lvalue, so
it can’t be incremented.
Next: Write Assignments Separately, Previous: Postincrement/Postdecrement, Up: Assignment Expressions [Contents][Index]
In C, the order of computing parts of an expression is not fixed.
Aside from a few special cases, the operations can be computed in any
order. If one part of the expression has an assignment to x
and another part of the expression uses x
, the result is
unpredictable because that use might be computed before or after the
assignment.
Here’s an example of ambiguous code:
x = 20; printf ("%d %d\n", x, x = 4);
If the second argument, x
, is computed before the third argument,
x = 4
, the second argument’s value will be 20. If they are
computed in the other order, the second argument’s value will be 4.
Here’s one way to make that code unambiguous:
y = 20; printf ("%d %d\n", y, x = 4);
Here’s another way, with the other meaning:
x = 4; printf ("%d %d\n", x, x);
This issue applies to all kinds of assignments, and to the increment and decrement operators, which are equivalent to assignments. See Order of Execution, for more information about this.
However, it can be useful to write assignments inside an
if
-condition or while
-test along with logical operators.
See Logicals and Assignments.
Previous: Assignment in Subexpressions, Up: Assignment Expressions [Contents][Index]
It is often convenient to write an assignment inside an
if
-condition, but that can reduce the readability of the
program. Here’s an example of what to avoid:
if (x = advance (x))
…
The idea here is to advance x
and test if the value is nonzero.
However, readers might miss the fact that it uses ‘=’ and not
‘==’. In fact, writing ‘=’ where ‘==’ was intended
inside a condition is a common error, so GNU C can give warnings when
‘=’ appears in a way that suggests it’s an error.
It is much clearer to write the assignment as a separate statement, like this:
x = advance (x);
if (x != 0)
…
This makes it unmistakably clear that x
is assigned a new value.
Another method is to use the comma operator (see Comma Operator), like this:
if (x = advance (x), x != 0)
…
However, putting the assignment in a separate statement is usually clearer unless the assignment is very short, because it reduces nesting.
Next: Binary Operator Grammar, Previous: Assignment Expressions, Up: Top [Contents][Index]
This chapter describes the C operators that combine expressions to control which of those expressions execute, or in which order.
| • Logical Operators | Logical conjunction, disjunction, negation. | |
| • Logicals and Comparison | Logical operators with comparison operators. | |
| • Logicals and Assignments | Assignments with logical operators. | |
| • Conditional Expression | An if/else construct inside expressions. | |
| • Comma Operator | Build a sequence of subexpressions. |
Next: Logicals and Comparison, Up: Execution Control Expressions [Contents][Index]
The logical operators combine truth values, which are normally
represented in C as numbers. Any expression with a numeric value is a
valid truth value: zero means false, and any other value means true.
A pointer type is also meaningful as a truth value; a null pointer
(which is zero) means false, and a non-null pointer means true
(see Pointer Types). The value of a logical operator is always 1
or 0 and has type int
(see Integer Types).
The logical operators are used mainly in the condition of an if
statement, or in the end test in a for
statement or
while
statement (see Statements). However, they are valid
in any context where an integer-valued expression is allowed.
Unary operator for logical “not.” The value is 1 (true) if exp is 0 (false), and 0 (false) if exp is nonzero (true).
Warning: if exp
is anything but an lvalue or a
function call, you should write parentheses around it.
The logical “and” binary operator computes left and, if necessary, right. If both of the operands are true, the ‘&&’ expression gives the value 1 (which is true). Otherwise, the ‘&&’ expression gives the value 0 (false). If left yields a false value, that determines the overall result, so right is not computed.
The logical “or” binary operator computes left and, if necessary, right. If at least one of the operands is true, the ‘||’ expression gives the value 1 (which is true). Otherwise, the ‘||’ expression gives the value 0 (false). If left yields a true value, that determines the overall result, so right is not computed.
Warning: never rely on the relative precedence of ‘&&’ and ‘||’. When you use them together, always use parentheses to specify explicitly how they nest, as shown here:
if ((r != 0 && x % r == 0) || (s != 0 && x % s == 0))
Next: Logicals and Assignments, Previous: Logical Operators, Up: Execution Control Expressions [Contents][Index]
The most common thing to use inside the logical operators is a comparison. Conveniently, ‘&&’ and ‘||’ have lower precedence than comparison operators and arithmetic operators, so we can write expressions like this without parentheses and get the nesting that is natural: two comparison operations that must both be true.
if (r != 0 && x % r == 0)
This example also shows how it is useful that ‘&&’ guarantees to skip the right operand if the left one turns out false. Because of that, this code never tries to divide by zero.
This is equivalent:
if (r && x % r == 0)
A truth value is simply a number, so r
as a truth value tests whether it is nonzero.
But r
’s meaning is not a truth value—it is a number to divide by.
So it is better style to write the explicit != 0
.
Here’s another equivalent way to write it:
if (!(r == 0) && x % r == 0)
This illustrates the unary ‘!’ operator, and the need to write parentheses around its operand.
Next: Conditional Expression, Previous: Logicals and Comparison, Up: Execution Control Expressions [Contents][Index]
There are cases where assignments nested inside the condition can
actually make a program easier to read. Here is an example
using a hypothetical type list
which represents a list; it
tests whether the list has at least two links, using hypothetical
functions, nonempty
which is true of the argument is a nonempty
list, and list_next
which advances from one list link to the
next. We assume that a list is never a null pointer, so that the
assignment expressions are always “true.”
if (nonempty (list) && (temp1 = list_next (list)) && nonempty (temp1) && (temp2 = list_next (temp1))) … /* usetemp1
andtemp2
*/
Here we get the benefit of the ‘&&’ operator, to avoid executing
the rest of the code if a call to nonempty
says “false.” The
only natural place to put the assignments is among those calls.
It would be possible to rewrite this as several statements, but that could make it much more cumbersome. On the other hand, when the test is even more complex than this one, splitting it into multiple statements might be necessary for clarity.
If an empty list is a null pointer, we can dispense with calling
nonempty
:
if ((temp1 = list_next (list))
&& (temp2 = list_next (temp1)))
…
Next: Comma Operator, Previous: Logicals and Assignments, Up: Execution Control Expressions [Contents][Index]
C has a conditional expression that selects one of two expressions to compute and get the value from. It looks like this:
condition ? iftrue : iffalse
| • Conditional Rules | Rules for the conditional operator. | |
| • Conditional Branches | About the two branches in a conditional. |
Next: Conditional Branches, Up: Conditional Expression [Contents][Index]
The first operand, condition, should be a value that can be compared with zero—a number or a pointer. If it is true (nonzero), then the conditional expression computes iftrue and its value becomes the value of the conditional expression. Otherwise the conditional expression computes iffalse and its value becomes the value of the conditional expression. The conditional expression always computes just one of iftrue and iffalse, never both of them.
Here’s an example: the absolute value of a number x
can be written as (x >= 0 ? x : -x)
.
Warning: The conditional expression operators have rather low syntactic precedence. Except when the conditional expression is used as an argument in a function call, write parentheses around it. For clarity, always write parentheses around it if it extends across more than one line.
Assignment operators and the comma operator (see Comma Operator) have lower precedence than conditional expression operators, so write parentheses around those when they appear inside a conditional expression. See Order of Execution.
Previous: Conditional Rules, Up: Conditional Expression [Contents][Index]
We call iftrue and iffalse the branches of the conditional.
The two branches should normally have the same type, but a few exceptions are allowed. If they are both numeric types, the conditional converts both to their common type (see Common Type).
With pointers (see Pointers), the two values can be pointers to nearly compatible types (see Compatible Types). In this case, the result type is a similar pointer whose target type combines all the type qualifiers (see Type Qualifiers) of both branches.
If one branch has type void *
and the other is a pointer to an
object (not to a function), the conditional converts the void *
branch to the type of the other.
If one branch is an integer constant with value zero and the other is a pointer, the conditional converts zero to the pointer’s type.
In GNU C, you can omit iftrue in a conditional expression. In that case, if condition is nonzero, its value becomes the value of the conditional expression, after conversion to the common type. Thus,
x ? : y
has the value of x
if that is nonzero; otherwise, the value of
y
.
Omitting iftrue is useful when condition has side effects.
In that case, writing that expression twice would carry out the side
effects twice, but writing it once does them just once. For example,
if we suppose that the function next_element
advances a pointer
variable to point to the next element in a list and returns the new
pointer,
next_element () ? : default_pointer
is a way to advance the pointer and use its new value if it isn’t
null, but use default_pointer
if that is null. We must not do
it this way,
next_element () ? next_element () : default_pointer
because it would advance the pointer a second time.
Previous: Conditional Expression, Up: Execution Control Expressions [Contents][Index]
The comma operator stands for sequential execution of expressions. The value of the comma expression comes from the last expression in the sequence; the previous expressions are computed only for their side effects. It looks like this:
exp1, exp2 …
You can bundle any number of expressions together this way, by putting commas between them.
| • Uses of Comma | When to use the comma operator. | |
| • Clean Comma | Clean use of the comma operator. | |
| • Avoid Comma | When to not use the comma operator. |
Next: Clean Comma, Up: Comma Operator [Contents][Index]
With commas, you can put several expressions into a place that
requires just one expression—for example, in the header of a
for
statement. This statement
for (i = 0, j = 10, k = 20; i < n; i++)
contains three assignment expressions, to initialize i
, j
and k
. The syntax of for
requires just one expression
for initialization; to include three assignments, we use commas to
bundle them into a single larger expression, i = 0, j = 10, k =
20
. This technique is also useful in the loop-advance expression,
the last of the three inside the for
parentheses.
In the for
statement and the while
statement
(see Loop Statements), a comma provides a way to perform some side
effect before the loop-exit test. For example,
while (printf ("At the test, x = %d\n", x), x != 0)
Next: Avoid Comma, Previous: Uses of Comma, Up: Comma Operator [Contents][Index]
Always write parentheses around a series of comma operators, except
when it is at top level in an expression statement, or within the
parentheses of an if
, for
, while
, or switch
statement (see Statements). For instance, in
for (i = 0, j = 10, k = 20; i < n; i++)
the commas between the assignments are clear because they are between a parenthesis and a semicolon.
The arguments in a function call are also separated by commas, but that is not an instance of the comma operator. Note the difference between
foo (4, 5, 6)
which passes three arguments to foo
and
foo ((4, 5, 6))
which uses the comma operator and passes just one argument (with value 6).
Warning: don’t use the comma operator around an argument of a function unless it helps understand the code. When you do so, don’t put part of another argument on the same line. Instead, add a line break to make the parentheses around the comma operator easier to see, like this.
foo ((mumble (x, y), frob (z)), *p)
Previous: Clean Comma, Up: Comma Operator [Contents][Index]
You can use a comma in any subexpression, but in most cases it only makes the code confusing, and it is clearer to raise all but the last of the comma-separated expressions to a higher level. Thus, instead of this:
x = (y += 4, 8);
it is much clearer to write this:
y += 4, x = 8;
or this:
y += 4; x = 8;
Use commas only in the cases where there is no clearer alternative involving multiple statements.
By contrast, don’t hesitate to use commas in the expansion in a macro definition. The trade-offs of code clarity are different in that case, because the use of the macro may improve overall clarity so much that the ugliness of the macro’s definition is a small price to pay. See Macros.
Next: Order of Execution, Previous: Execution Control Expressions, Up: Top [Contents][Index]
Binary operators are those that take two operands, one on the left and one on the right.
All the binary operators in C are syntactically left-associative.
This means that a op b op c
means (a op b) op c
. However, you should only write repeated
operators without parentheses using ‘+’, ‘-’, ‘*’ and
‘/’, because those cases are clear from algebra. So it is ok to
write a + b + c
or a - b - c
, but never a == b ==
c
or a % b % c
.
Each C operator has a precedence, which is its rank in the grammatical order of the various operators. The operators with the highest precedence grab adjoining operands first; these expressions then become operands for operators of lower precedence.
The precedence order of operators in C is fully specified, so any combination of operations leads to a well-defined nesting. We state only part of the full precedence ordering here because it is bad practice for C code to depend on the other cases. For cases not specified in this chapter, always use parentheses to make the nesting explicit.2
You can depend on this subsequence of the precedence ordering (stated from highest precedence to lowest):
Two of the lines in the above list say “but watch out!” That means that the line covers operators with subtly different precedence. Never depend on the grammar of C to decide how two comparisons nest; instead, always use parentheses to specify their nesting.
You can let several ‘&&’ operators associate, or several ‘||’ operators, but always use parentheses to show how ‘&&’ and ‘||’ nest with each other. See Logical Operators.
There is one other precedence ordering that code can depend on:
The caveat for bitwise and shift operators is like that for logical operators: you can let multiple uses of one bitwise operator associate, but always use parentheses to control nesting of dissimilar operators.
These lists do not specify any precedence ordering between the bitwise and shift operators of the second list and the binary operators above conditional expressions in the first list. When they come together, parenthesize them. See Bitwise Operations.
Next: Primitive Types, Previous: Binary Operator Grammar, Up: Top [Contents][Index]
The order of execution of a C program is not always obvious, and not necessarily predictable. This chapter describes what you can count on.
| • Reordering of Operands | Operations in C are not necessarily computed in the order they are written. | |
| • Associativity and Ordering | Some associative operations are performed in a particular order; others are not. | |
| • Sequence Points | Some guarantees about the order of operations. | |
| • Postincrement and Ordering | Ambiguous excution order with postincrement. | |
| • Ordering of Operands | Evaluation order of operands and function arguments. | |
| • Optimization and Ordering | Compiler optimizations can reorder operations only if it has no impact on program results. |
Next: Associativity and Ordering, Up: Order of Execution [Contents][Index]
The C language does not necessarily carry out operations within an expression in the order they appear in the code. For instance, in this expression,
foo () + bar ()
foo
might be called first or bar
might be called first.
If foo
updates a datum and bar
uses that datum, the
results can be unpredictable.
The unpredictable order of computation of subexpressions also makes a difference when one of them contains an assignment. We already saw this example of bad code,
x = 20; printf ("%d %d\n", x, x = 4);
in which the second argument, x
, has a different value
depending on whether it is computed before or after the assignment in
the third argument.
Next: Sequence Points, Previous: Reordering of Operands, Up: Order of Execution [Contents][Index]
An associative binary operator, such as +
, when used repeatedly
can combine any number of operands. The operands’ values may be
computed in any order.
If the values are integers and overflow can be ignored, they may be
combined in any order. Thus, given four functions that return
unsigned int
, calling them and adding their results as here
(foo () + bar ()) + (baz () + quux ())
may add up the results in any order.
By contrast, arithmetic on signed integers, with overflow significant,
is not really associative (see Integer Overflow). Thus, the
additions must be done in the order specified, obeying parentheses and
left-association. That means computing (foo () + bar ())
and
(baz () + quux ())
first (in either order), then adding the
two.
The same applies to arithmetic on floating-point values, since that too is not really associative. However, the GCC option -funsafe-math-optimizations allows the compiler to change the order of calculation when an associative operation (associative in exact mathematics) combines several operands. The option takes effect when compiling a module (see Compilation). Changing the order of association can enable the program to pipeline the floating point operations.
In all these cases, the four function calls can be done in any order. There is no right or wrong about that.
Next: Postincrement and Ordering, Previous: Associativity and Ordering, Up: Order of Execution [Contents][Index]
There are some points in the code where C makes limited guarantees about the order of operations. These are called sequence points. Here is where they occur:
The commas that separate arguments in a function call are not comma operators, and they do not create sequence points. The rule for function arguments and the rule for operands are different (see Ordering of Operands).
If the function to be called is not constant—that is, if it is computed by an expression—all side effects in that expression are carried out before calling the function.
The ordering imposed by a sequence point applies locally to a limited range of code, as stated above in each case. For instance, the ordering imposed by the comma operator does not apply to code outside that comma operator. Thus, in this code,
(x = 5, foo (x)) + x * x
the sequence point of the comma operator orders x = 5
before
foo (x)
, but x * x
could be computed before or after
them.
Next: Ordering of Operands, Previous: Sequence Points, Up: Order of Execution [Contents][Index]
Ordering requirements are loose with the postincrement and postdecrement operations (see Postincrement/Postdecrement), which specify side effects to happen “a little later.” They must happen before the next sequence point, but that still leaves room for various meanings. In this expression,
z = x++ - foo ()
it’s unpredictable whether x
gets incremented before or after
calling the function foo
. If foo
refers to x
,
it might see the old value or it might see the incremented value.
In this perverse expression,
x = x++
x
will certainly be incremented but the incremented value may
not stick. If the incrementation of x
happens after the
assignment to x
, the incremented value will remain in place.
But if the incrementation happens first, the assignment will overwrite
that with the not-yet-incremented value, so the expression as a whole
will leave x
unchanged.
Next: Optimization and Ordering, Previous: Postincrement and Ordering, Up: Order of Execution [Contents][Index]
Operands and arguments can be computed in any order, but there are limits to this intermixing in GNU C:
These rules don’t cover side effects caused by postincrement and postdecrement operators—those can be deferred up to the next sequence point.
If you want to get pedantic, the fact is that GCC can reorder the
computations in many other ways provided that doesn’t alter the result
of running the program. However, because they don’t alter the result
of running the program, they are negligible, unless you are concerned
with the values in certain variables at various times as seen by other
processes. In those cases, you can use volatile
to prevent
optimizations that would make them behave strangely. See volatile.
Previous: Ordering of Operands, Up: Order of Execution [Contents][Index]
Sequence points limit the compiler’s freedom to reorder operations arbitrarily, but optimizations can still reorder them if the compiler concludes that this won’t alter the results. Thus, in this code,
x++; y = z; x++;
there is a sequence point after each statement, so the code is
supposed to increment x
once before the assignment to y
and once after. However, incrementing x
has no effect on
y
or z
, and setting y
can’t affect x
, so
the code could be optimized into this:
y = z; x += 2;
Normally that has no effect except to make the program faster. But
there are special situations where it can cause trouble due to things
that the compiler cannot know about, such as shared memory. To limit
optimization in those places, use the volatile
type qualifier
(see volatile).
Next: Constants, Previous: Order of Execution, Up: Top [Contents][Index]
This chapter describes all the primitive data types of C—that is,
all the data types that aren’t built up from other types. They
include the types int
and double
that we’ve already covered.
| • Integer Types | Description of integer types. | |
| • Floating-Point Data Types | Description of floating-point types. | |
| • Complex Data Types | Description of complex number types. | |
| • The Void Type | A type indicating no value at all. | |
| • Other Data Types | A brief summary of other types. | |
| • Type Designators | Referring to a data type abstractly. |
These types are all made up of bytes (see Storage).
Next: Floating-Point Data Types, Up: Primitive Types [Contents][Index]
Here we describe all the integer types and their basic characteristics. See Integers in Depth, for more information about the bit-level integer data representations and arithmetic.
| • Basic Integers | Overview of the various kinds of integers. | |
| • Signed and Unsigned Types | Integers can either hold both negative and non-negative values, or only non-negative. | |
| • Narrow Integers | When to use smaller integer types. | |
| • Integer Conversion | Casting a value from one integer type to another. | |
| • Boolean Type | An integer type for boolean values. | |
| • Integer Variations | Sizes of integer types can vary across platforms. |
Next: Signed and Unsigned Types, Up: Integer Types [Contents][Index]
Integer data types in C can be signed or unsigned. An unsigned type can represent only positive numbers and zero. A signed type can represent both positive and negative numbers, in a range spread almost equally on both sides of zero.
Aside from signedness, the integer data types vary in size: how many bytes long they are. The size determines how many different integer values the type can hold.
Here’s a list of the signed integer data types, with the sizes they have on most computers. Each has a corresponding unsigned type; see Signed and Unsigned Types.
signed char
One byte (8 bits). This integer type is used mainly for integers that represent characters, as part of arrays or other data structures.
short
short int
Two bytes (16 bits).
int
Four bytes (32 bits).
long
long int
Four bytes (32 bits) or eight bytes (64 bits), depending on the platform. Typically it is 32 bits on 32-bit computers and 64 bits on 64-bit computers, but there are exceptions.
long long
long long int
Eight bytes (64 bits). Supported in GNU C in the 1980s, and incorporated into standard C as of ISO C99.
You can omit int
when you use long
or short
.
This is harmless and customary.
Next: Narrow Integers, Previous: Basic Integers, Up: Integer Types [Contents][Index]
An unsigned integer type can represent only positive numbers and zero.
A signed type can represent both positive and negative number, in a
range spread almost equally on both sides of zero. For instance,
unsigned char
holds numbers from 0 to 255 (on most computers),
while signed char
holds numbers from -128 to 127. Each of
these types holds 256 different possible values, since they are both 8
bits wide.
Write signed
or unsigned
before the type keyword to
specify a signed or an unsigned type. However, the integer types
other than char
are signed by default; with them, signed
is a no-op.
Plain char
may be signed or unsigned; this depends on the
compiler, the machine in use, and its operating system.
In many programs, it makes no difference whether char
is
signed. When it does matter, don’t leave it to chance; write
signed char
or unsigned char
.3
Next: Integer Conversion, Previous: Signed and Unsigned Types, Up: Integer Types [Contents][Index]
The types that are narrower than int
are rarely used for
ordinary variables—we declare them int
instead. This is
because C converts those narrower types to int
for any
arithmetic. There is literally no reason to declare a local variable
char
, for instance.
In particular, if the value is really a character, you should declare
the variable int
. Not char
! Using that narrow type can
force the compiler to truncate values for conversion, which is a
waste. Furthermore, some functions return either a character value,
or -1 for “no character.” Using int
keeps those
values distinct.
The narrow integer types are useful as parts of other objects, such as arrays and structures. Compare these array declarations, whose sizes on 32-bit processors are shown:
signed char ac[1000]; /* 1000 bytes */ short as[1000]; /* 2000 bytes */ int ai[1000]; /* 4000 bytes */ long long all[1000]; /* 8000 bytes */
In addition, character strings must be made up of char
s,
because that’s what all the standard library string functions expect.
Thus, array ac
could be used as a character string, but the
others could not be.
Next: Boolean Type, Previous: Narrow Integers, Up: Integer Types [Contents][Index]
C converts between integer types implicitly in many situations. It
converts the narrow integer types, char
and short
, to
int
whenever they are used in arithmetic. Assigning a new
value to an integer variable (or other lvalue) converts the value to
the variable’s type.
You can also convert one integer type to another explicitly with a cast operator. See Explicit Type Conversion.
The process of conversion to a wider type is straightforward: the value is unchanged. The only exception is when converting a negative value (in a signed type, obviously) to a wider unsigned type. In that case, the result is a positive value with the same bits (see Integers in Depth).
Converting to a narrower type, also called truncation, involves discarding some of the value’s bits. This is not considered overflow (see Integer Overflow) because loss of significant bits is a normal consequence of truncation. Likewise for conversion between signed and unsigned types of the same width.
More information about conversion for assignment is in Assignment Type Conversions. For conversion for arithmetic, see Argument Promotions.
Next: Integer Variations, Previous: Integer Conversion, Up: Integer Types [Contents][Index]
The unsigned integer type bool
holds truth values: its possible
values are 0 and 1. Converting any nonzero value to bool
results in 1. For example:
bool a = 0;
bool b = 1;
bool c = 4; /* Stores the value 1 in c
. */
Unlike int
, bool
is not a keyword. It is defined in
the header file stdbool.h.
Previous: Boolean Type, Up: Integer Types [Contents][Index]
The integer types of C have standard names, but what they mean varies depending on the kind of platform in use: which kind of computer, which operating system, and which compiler. It may even depend on the compiler options used.
Plain char
may be signed or unsigned; this depends on the
platform, too. Even for GNU C, there is no general rule.
In theory, all of the integer types’ sizes can vary. char
is
always considered one “byte” for C, but it is not necessarily an
8-bit byte; on some platforms it may be more than 8 bits. ISO C
specifies only that none of these types is narrower than the ones
above it in the list in Basic Integers, and that short
has at least 16 bits.
It is possible that in the future GNU C will support platforms where
int
is 64 bits long. In practice, however, on today’s real
computers, there is little variation; you can rely on the table
given previously (see Basic Integers).
To be completely sure of the size of an integer type,
use the types int16_t
, int32_t
and int64_t
.
Their corresponding unsigned types add ‘u’ at the front.
To define these, include the header file stdint.h.
The GNU C Compiler compiles for some embedded controllers that use two
bytes for int
. On some, int
is just one “byte,” and
so is short int
—but that “byte” may contain 16 bits or even
32 bits. These processors can’t support an ordinary operating system
(they may have their own specialized operating systems), and most C
programs do not try to support them.
Next: Complex Data Types, Previous: Integer Types, Up: Primitive Types [Contents][Index]
Floating point is the binary analogue of scientific notation: internally it represents a number as a fraction and a binary exponent; the value is that fraction multiplied by the specified power of 2.
For instance, to represent 6, the fraction would be 0.75 and the exponent would be 3; together they stand for the value 0.75 * 23, meaning 0.75 * 8. The value 1.5 would use 0.75 as the fraction and 1 as the exponent. The value 0.75 would use 0.75 as the fraction and 0 as the exponent. The value 0.375 would use 0.75 as the fraction and -1 as the exponent.
These binary exponents are used by machine instructions. You can write a floating-point constant this way if you wish, using hexadecimal; but normally we write floating-point numbers in decimal. See Floating Constants.
C has three floating-point data types:
double
“Double-precision” floating point, which uses 64 bits. This is the normal floating-point type, and modern computers normally do their floating-point computations in this type, or some wider type. Except when there is a special reason to do otherwise, this is the type to use for floating-point values.
float
“Single-precision” floating point, which uses 32 bits. It is useful
for floating-point values stored in structures and arrays, to save
space when the full precision of double
is not needed. In
addition, single-precision arithmetic is faster on some computers, and
occasionally that is useful. But not often—most programs don’t use
the type float
.
C would be cleaner if float
were the name of the type we
use for most floating-point values; however, for historical reasons,
that’s not so.
long double
“Extended-precision” floating point is either 80-bit or 128-bit
precision, depending on the machine in use. On some machines, which
have no floating-point format wider than double
, this is
equivalent to double
.
Floating-point arithmetic raises many subtle issues. See Floating Point in Depth, for more information.
Next: The Void Type, Previous: Floating-Point Data Types, Up: Primitive Types [Contents][Index]
Complex numbers can include both a real part and an imaginary part. The numeric constants covered above have real-numbered values. An imaginary-valued constant is an ordinary real-valued constant followed by ‘i’.
To declare numeric variables as complex, use the _Complex
keyword.4 The
standard C complex data types are floating point,
_Complex float foo; _Complex double bar; _Complex long double quux;
but GNU C supports integer complex types as well.
Since _Complex
is a keyword just like float
and
double
and long
, the keywords can appear in any order,
but the order shown above seems most logical.
GNU C supports constants for complex values; for instance, 4.0 +
3.0i
has the value 4 + 3i as type _Complex double
.
See Imaginary Constants.
To pull the real and imaginary parts of the number back out, GNU C
provides the keywords __real__
and __imag__
:
_Complex double foo = 4.0 + 3.0i; double a = __real__ foo; /*a
is now 4.0. */ double b = __imag__ foo; /*b
is now 3.0. */
Standard C does not include these keywords, and instead relies on
functions defined in complex.h
for accessing the real and
imaginary parts of a complex number: crealf
, creal
, and
creall
extract the real part of a float, double, or long double
complex number, respectively; cimagf
, cimag
, and
cimagl
extract the imaginary part.
GNU C also defines ‘~’ as an operator for complex conjugation, which means negating the imaginary part of a complex number:
_Complex double foo = 4.0 + 3.0i;
_Complex double bar = ~foo; /* bar
is now 4 - 3i. */
For standard C compatibility, you can use the appropriate library
function: conjf
, conj
, or confl
.
Next: Other Data Types, Previous: Complex Data Types, Up: Primitive Types [Contents][Index]
The data type void
is a dummy—it allows no operations. It
really means “no value at all.” When a function is meant to return
no value, we write void
for its return type. Then
return
statements in that function should not specify a value
(see return Statement). Here’s an example:
void print_if_positive (double x, double y) { if (x <= 0) return; if (y <= 0) return; printf ("Next point is (%f,%f)\n", x, y); }
A void
-returning function is comparable to what some other languages
call a “procedure” instead of a “function.”
Next: Type Designators, Previous: The Void Type, Up: Primitive Types [Contents][Index]
Beyond the primitive types, C provides several ways to construct new data types. For instance, you can define pointers, values that represent the addresses of other data (see Pointers). You can define structures, as in many other languages (see Structures), and unions, which specify multiple ways to look at the same memory space (see Unions). Enumerations are collections of named integer codes (see Enumeration Types).
Array types in C are used for allocating space for objects, but C does not permit operating on an array value as a whole. See Arrays.
Previous: Other Data Types, Up: Primitive Types [Contents][Index]
Some C constructs require a way to designate a specific data type
independent of any particular variable or expression which has that
type. The way to do this is with a type designator. The
constucts that need one include casts (see Explicit Type Conversion) and sizeof
(see Type Size).
We also use type designators to talk about the type of a value in C,
so you will see many type designators in this manual. When we say,
“The value has type int
,” int
is a type designator.
To make the designator for any type, imagine a variable declaration for a variable of that type and delete the variable name and the final semicolon.
For example, to designate the type of full-word integers, we start
with the declaration for a variable foo
with that type,
which is this:
int foo;
Then we delete the variable name foo
and the semicolon, leaving
int
—exactly the keyword used in such a declaration.
Therefore, the type designator for this type is int
.
What about long unsigned integers? From the declaration
unsigned long int foo;
we determine that the designator is unsigned long int
.
Following this procedure, the designator for any primitive type is simply the set of keywords which specifies that type in a declaration. The same is true for compound types such as structures, unions, and enumerations.
Designators for pointer types do follow the rule of deleting the variable name and semicolon, but the result is not so simple. See Pointer Type Designators, as part of the chapter about pointers. See Array Type Designators), for designators for array types.
To understand what type a designator stands for, imagine a variable name inserted into the right place in the designator to make a valid declaration. What type would that variable be declared as? That is the type the designator designates.
Next: Type Size, Previous: Primitive Types, Up: Top [Contents][Index]
A constant is an expression that stands for a specific value by explicitly representing the desired value. C allows constants for numbers, characters, and strings. We have already seen numeric and string constants in the examples.
| • Integer Constants | Literal integer values. | |
| • Integer Const Type | Types of literal integer values. | |
| • Floating Constants | Literal floating-point values. | |
| • Imaginary Constants | Literal imaginary number values. | |
| • Invalid Numbers | Avoiding preprocessing number misconceptions. | |
| • Character Constants | Literal character values. | |
| • String Constants | Literal string values. | |
| • UTF-8 String Constants | Literal UTF-8 string values. | |
| • Unicode Character Codes | Unicode characters represented in either UTF-16 or UTF-32. | |
| • Wide Character Constants | Literal characters values larger than 8 bits. | |
| • Wide String Constants | Literal string values made up of 16- or 32-bit characters. |
Next: Integer Const Type, Up: Constants [Contents][Index]
An integer constant consists of a number to specify the value, followed optionally by suffix letters to specify the data type.
The simplest integer constants are numbers written in base 10
(decimal), such as 5
, 77
, and 403
. A decimal
constant cannot start with the character ‘0’ (zero) because
that makes the constant octal.
You can get the effect of a negative integer constant by putting a minus sign at the beginning. Grammatically speaking, that is an arithmetic expression rather than a constant, but it behaves just like a true constant.
Integer constants can also be written in octal (base 8), hexadecimal (base 16), or binary (base 2). An octal constant starts with the character ‘0’ (zero), followed by any number of octal digits (‘0’ to ‘7’):
0 // zero 077 // 63 0403 // 259
Pedantically speaking, the constant 0
is an octal constant, but
we can think of it as decimal; it has the same value either way.
A hexadecimal constant starts with ‘0x’ (upper or lower case) followed by hex digits (‘0’ to ‘9’, as well as ‘a’ through ‘f’ in upper or lower case):
0xff // 255 0XA0 // 160 0xffFF // 65535
A binary constant starts with ‘0b’ (upper or lower case) followed by bits (each represented by the characters ‘0’ or ‘1’):
0b101 // 5
Binary constants are a GNU C extension, not part of the C standard.
Sometimes a space is needed after an integer constant to avoid lexical confusion with the following tokens. See Invalid Numbers.
Next: Floating Constants, Previous: Integer Constants, Up: Constants [Contents][Index]
The type of an integer constant is normally int
, if the value
fits in that type, but here are the complete rules. The type
of an integer constant is the first one in this sequence that can
properly represent the value,
int
unsigned int
long int
unsigned long int
long long int
unsigned long long int
and that isn’t excluded by the following rules.
If the constant has ‘l’ or ‘L’ as a suffix, that excludes the
first two types (non-long
).
If the constant has ‘ll’ or ‘LL’ as a suffix, that excludes
first four types (non-long long
).
If the constant has ‘u’ or ‘U’ as a suffix, that excludes the signed types.
Otherwise, if the constant is decimal, that excludes the unsigned types.
Here are some examples of the suffixes.
3000000000u // three billion asunsigned int
. 0LL // zero as along long int
. 0403l // 259 as along int
.
Suffixes in integer constants are rarely used. When the precise type is important, it is cleaner to convert explicitly (see Explicit Type Conversion).
See Integer Types.
Next: Imaginary Constants, Previous: Integer Const Type, Up: Constants [Contents][Index]
A floating-point constant must have either a decimal point, an exponent-of-ten, or both; they distinguish it from an integer constant.
To indicate an exponent, write ‘e’ or ‘E’. The exponent value follows. It is always written as a decimal number; it can optionally start with a sign. The exponent n means to multiply the constant’s value by ten to the nth power.
Thus, ‘1500.0’, ‘15e2’, ‘15e+2’, ‘15.0e2’, ‘1.5e+3’, ‘.15e4’, and ‘15000e-1’ are six ways of writing a floating-point number whose value is 1500. They are all equivalent.
Here are more examples with decimal points:
1.0 1000. 3.14159 .05 .0005
For each of them, here are some equivalent constants written with exponents:
1e0, 1.0000e0 100e1, 100e+1, 100E+1, 1e3, 10000e-1 3.14159e0 5e-2, .0005e+2, 5E-2, .0005E2 .05e-2
A floating-point constant normally has type double
. You can
force it to type float
by adding ‘f’ or ‘F’
at the end. For example,
3.14159f 3.14159e0f 1000.f 100E1F .0005f .05e-2f
Likewise, ‘l’ or ‘L’ at the end forces the constant
to type long double
.
You can use exponents in hexadecimal floating constants, but since ‘e’ would be interpreted as a hexadecimal digit, the character ‘p’ or ‘P’ (for “power”) indicates an exponent.