digital design and computer architecture: arm® edition

49
eC C Programming C.1 INTRODUCTION The overall goal of this book is to give a picture of how computers work on many levels, from the transistors by which they are constructed all the way up to the software they run. The first five chapters of this book work up through the lower levels of abstraction, from transistors to gates to logic design. Chapters 6 through 8 jump up to architecture and work back down to micro- architecture to connect the hardware with the software. This Appendix on C programming fits logically between Chapters 5 and 6, covering C program- ming as the highest level of abstraction in the text. It motivates the architec- ture material and links this book to programming experience that may already be familiar to the reader. This material is placed in the Appendix so that readers may easily cover or skip it depending on previous experience. Programmers use many different languages to tell a computer what to do. Fundamentally, computers process instructions in machine language consisting of 1s and 0s, as is explored in Chapter 6. But programming in machine language is tedious and slow, leading programmers to use more abstract languages to get their meaning across more efficiently. Table eC.1 lists some examples of languages at various levels of abstraction. One of the most popular programming languages ever developed is called C. It was created by a group including Dennis Ritchie and Brian Kernighan at Bell Laboratories between 1969 and 1973 to rewrite the UNIX operating system from its original assembly language. By many measures, C (including a family of closely related languages such as C++, C#, and Objective C) is the most widely used language in existence. Its popularity stems from a number of factors including its: Availability on a tremendous variety of platforms, from supercomputers down to embedded microcontrollers Relative ease of use, with a huge user base C.1 Introduction C.2 Welcome to C C.3 Compilation C.4 Variables C.5 Operators C.6 Function Calls C.7 Control-Flow Statements C.8 More Data Types C.9 Standard Libraries C.10 Compiler and Command Line Options C.11 Common Mistakes + + Physics Devices Analog Circuits Digital Circuits Logic Micro- architecture Architecture Operating Systems Application Software >”hello world!” Digital Design and Computer Architecture, Second Edition. DOI: 10.1016/B978-0-12-394424-5.00017-3 © 2013 Elsevier, Inc. All rights reserved. 541.e1

Upload: others

Post on 27-Dec-2021

3 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: Digital Design and Computer Architecture: ARM® Edition

eCC Programming

C.1 INTRODUCTION

The overall goal of this book is to give a picture of how computers work onmany levels, from the transistors bywhich they are constructed all theway upto the software they run. The first five chapters of this bookwork up throughthe lower levels of abstraction, from transistors to gates to logic design.Chapters 6 through 8 jump up to architecture andwork back down tomicro-architecture to connect the hardware with the software. This Appendix on Cprogramming fits logically between Chapters 5 and 6, covering C program-ming as the highest level of abstraction in the text. It motivates the architec-ture material and links this book to programming experience that mayalready be familiar to the reader. This material is placed in the Appendixso that readers may easily cover or skip it depending on previous experience.

Programmers use many different languages to tell a computer what todo. Fundamentally, computers process instructions in machine languageconsisting of 1’s and 0’s, as is explored in Chapter 6. But programmingin machine language is tedious and slow, leading programmers to use moreabstract languages to get their meaning across more efficiently. Table eC.1lists some examples of languages at various levels of abstraction.

One of the most popular programming languages ever developed iscalled C. It was created by a group including Dennis Ritchie and BrianKernighan at Bell Laboratories between 1969 and 1973 to rewrite theUNIX operating system from its original assembly language. By manymeasures, C (including a family of closely related languages such as C++,C#, and Objective C) is the most widely used language in existence. Itspopularity stems from a number of factors including its:

▶ Availability on a tremendous variety of platforms, from supercomputersdown to embedded microcontrollers

▶ Relative ease of use, with a huge user base

C.1 Introduction

C.2 Welcome to C

C.3 Compilation

C.4 Variables

C.5 Operators

C.6 Function Calls

C.7 Control-Flow Statements

C.8 More Data Types

C.9 Standard Libraries

C.10 Compiler and Command LineOptions

C.11 Common Mistakes

+

+−

Physics

Devices

AnalogCircuits

DigitalCircuits

Logic

Micro-architecture

Architecture

OperatingSystems

ApplicationSoftware

>”helloworld!”

Digital Design and Computer Architecture, Second Edition. DOI: 10.1016/B978-0-12-394424-5.00017-3© 2013 Elsevier, Inc. All rights reserved.

541.e1

Page 2: Digital Design and Computer Architecture: ARM® Edition

▶ Moderate level of abstraction providing higher productivity thanassembly language, yet giving the programmer a good understandingof how the code will be executed

▶ Suitability for generating high performance programs

▶ Ability to interact directly with the hardware

This chapter is devoted to C programming for a variety of reasons. Mostimportantly, C allows the programmer to directly access addresses inmemory, illustrating the connection between hardware and softwareemphasized in this book. C is a practical language that all engineersand computer scientists should know. Its uses in many aspects of implemen-tation and design – e.g., software development, embedded systems program-ming, and simulation – make proficiency in C a vital and marketable skill.

The following sections describe the overall syntax of a C program, dis-cussing each part of the program including the header, function and variabledeclarations, data types, and commonly used functions provided in libraries.Chapter 9 (available as a web supplement, see Preface) describes a hands-onapplication by using C to program an ARM-based Raspberry Pi computer.

SUMMARY▶ High-level programming: High-level programming is useful at many

levels of design, from writing analysis or simulation software toprogramming microcontrollers that interact with hardware.

▶ Low-level access: C code is powerful because, in addition to high-level constructs, it provides access to low-level hardware and memory.

Table eC.1 Languages at roughly decreasing levels of abstraction

Language Description

Matlab Designed to facilitate heavy use of math functions

Perl Designed for scripting

Python Designed to emphasize code readability

Java Designed to run securely on any computer

C Designed for flexibility and overall system access,including device drivers

Assembly Language Human-readable machine language

Machine Language Binary representation of a program

Dennis Ritchie, 1941–2011

Brian Kernighan, 1942–

C was formally introduced in1978 by Brian Kernighan andDennis Ritchie’s classic book,The C Programming Language.In 1989, the American NationalStandards Institute (ANSI)expanded and standardized thelanguage, which became knownas ANSI C, Standard C, or C89.Shortly thereafter, in 1990, thisstandard was adopted by theInternational Organization forStandardization (ISO) and theInternational ElectrotechnicalCommission (IEC). ISO/IECupdated the standard in 1999to what is called C99, whichwe will be discussing in this text.

541.e2 APPENDIX C

Page 3: Digital Design and Computer Architecture: ARM® Edition

C.2 WELCOME TO C

A C program is a text file that describes operations for the computerto perform. The text file is compiled, converted into a machine-readableformat, and run or executed on a computer. C Code Example eC.1 is asimple C program that prints the phrase “Hello world!” to the console,the computer screen. C programs are generally contained in one or moretext files that end in “.c”. Good programming style requires a file namethat indicates the contents of the program – for example, this file couldbe called hello.c.

C . 2 . 1 C Program Dissection

In general, a C program is organized into one or more functions. Everyprogram must include the main function, which is where the programstarts executing. Most programs use other functions defined elsewherein the C code and/or in a library. The overall sections of the hello.cprogram are the header, the main function, and the body.

Header: #include <stdio.h>The header includes the library functions needed by the program. In this case,the program uses the printf function, which is part of the standard I/Olibrary, stdio.h. See Section C.9 for further details on C’s built-in libraries.

Main function: int main(void)All C programs must include exactly one main function. Execution of theprogram occurs by running the code inside main, called the body of main.Function syntax is described in Section C.6. The body of a function con-tains a sequence of statements. Each statement ends with a semicolon. intdenotes that the main function outputs, or returns, an integer result thatindicates whether the program ran successfully.

C is the language used toprogram such ubiquitoussystems as Linux, Windows,and iOS. C is a powerfullanguage because of its directaccess to hardware. Ascompared with other highlevel languages, for examplePerl and Matlab, C does nothave as much built-in supportfor specialized operationssuch as file manipulation,pattern matching, matrixmanipulation, and graphicaluser interfaces. It also lacksfeatures to protect theprogrammer from commonmistakes, such as writing datapast the end of an array. Itspower combined with its lackof protection has assistedhackers who exploit poorlywritten software to breakinto computer systems.

While this chapter provides afundamental understanding ofC programming, entire textsare written that describe C indepth. One of our favorites isthe classic text The CProgramming Language byBrian Kernighan and DennisRitchie, the developers of C.This text gives a concisedescription of the nuts andbolts of C. Another good textis A Book on C by Al Kelleyand Ira Pohl.

C Code Example eC.1 SIMPLE C PROGRAM

// Write "Hello world!" to the console

#include <stdio.h>

int main(void){

printf("Hello world!\n");

}

Console Output

Hello world!

C.2 Welcome to C 541.e3

Page 4: Digital Design and Computer Architecture: ARM® Edition

Body: printf("Hello world!\n");The body of this main function contains one statement, a call to theprintf function, which prints the phrase “Hello world!” followed by anewline character indicated by the special sequence "\n". Further detailsabout I/O functions are described in Section C.9.1.

All programs follow the general format of the simple hello.c pro-gram. Of course, very complex programs may contain millions of linesof code and span hundreds of files.

C . 2 . 2 Running a C Program

C programs can be run on many different machines. This portability isanother advantage of C. The program is first compiled on the desiredmachineusing theC compiler. Slightly different versions of the C compiler exist, includ-ing cc (C compiler), or gcc (GNU C compiler). Here we show how to compileand run a C program using gcc, which is freely available for download. It runsdirectly on Linux machines and is accessible under the Cygwin environmenton Windows machines. It is also available for many embedded systems suchas the ARM-based Raspberry Pi. The general process described below of Cfile creation, compilation, and execution is the same for any C program.

1. Create the text file, for example hello.c.

2. In a terminal window, change to the directory that contains the filehello.c and type gcc hello.c at the command prompt.

3. The compiler creates an executable file. By default, the executable iscalled a.out (or a.exe on Windows machines).

4. At the command prompt, type ./a.out (or ./a.exe on Windows)and press return.

5. “Hello world!” will appear on the screen.

SUMMARY▶ filename.c: C program files are typically named with a .c extension.

▶ main: Each C program must have exactly one main function.

▶ #include: Most C programs use functions provided by built-inlibraries. These functions are used by writing #include <library.h>at the top of the C file.

▶ gcc filename.c: C files are converted into an executable using acompiler such as the GNU compiler (gcc) or the C compiler (cc).

▶ Execution: After compilation, C programs are executed by typing./a.out (or ./a.exe) at the command line prompt.

541.e4 APPENDIX C

Page 5: Digital Design and Computer Architecture: ARM® Edition

C.3 COMPILATION

A compiler is a piece of software that reads a program in a high-levellanguage and converts it into a file of machine code called an executable.Entire textbooks are written on compilers, but we describe them here briefly.The overall operation of the compiler is to (1) preprocess the file by includingreferenced libraries and expanding macro definitions, (2) ignore all unneces-sary information such as comments, (3) translate the high-level code intosimple instructions native to the processor that are represented in binary,called machine language, and (4) compile all the instructions into a singlebinary executable that can be read and executed by the computer. Eachmachine language is specific to a given processor, so a program must becompiled specifically for the system on which it will run. For example, theARM machine language is covered in Chapter 6 in detail.

C . 3 . 1 Comments

Programmers use comments to describe code at a high-level and clarifycode function. Anyone who has read uncommented code can attest totheir importance. C programs use two types of comments: Single-linecomments begin with // and terminate at the end of the line; multiple-linecomments begin with /* and end with */. While comments are critical tothe organization and clarity of a program, they are ignored by thecompiler.

// This is an example of a one-line comment.

/* This is an exampleof a multi-line comment. */

A comment at the top of each C file is useful to describe the file’s author,creation and modification dates, and purpose. The comment below couldbe included at the top of the hello.c file.

// hello.c// 1 Jan 2015 [email protected], [email protected]//// This program prints "Hello world!" to the screen

C . 3 . 2 #define

Constants are named using the #define directive and then used by namethroughout the program. These globally defined constants are also calledmacros. For example, suppose you write a program that allows at most5 user guesses, you can use #define to identify that number.

#define MAXGUESSES 5

C.3 Compilation 541.e5

Page 6: Digital Design and Computer Architecture: ARM® Edition

The # indicates that this line in the program will be handled by the pre-processor. Before compilation, the preprocessor replaces each occurrenceof the identifier MAXGUESSES in the program with 5. By convention,#define lines are located at the top of the file and identifiers are writtenin all capital letters. By defining constants in one location and then usingthe identifier in the program, the program remains consistent, and thevalue is easily modified – it need only be changed at the #define lineinstead of at each line in the code where the value is needed.

C Code Example eC.2 shows how to use the #define directive toconvert inches to centimeters. The variables inch and cm are declared tobe float to indicate they represent single-precision floating point num-bers. If the conversion factor (INCH2CM) were used throughout a largeprogram, having it declared using #define obviates errors due to typos(for example, typing 2.53 instead of 2.54) and makes it easy to find andchange (for example, if more significant digits were required).

C . 3 . 3 #include

Modularity encourages us to split programs across separate files and func-tions. Commonly used functions can be grouped together for easy reuse.Variable declarations, defined values, and function definitions located in aheader file can be used by another file by adding the #include preprocesserdirective. Standard libraries that provide commonly used functions areaccessed in this way. For example, the following line is required to use thefunctions defined in the standard input/output (I/O) library, such as printf.

#include <stdio.h>

The “.h” postfix of the include file indicates it is a header file. While#include directives can be placed anywhere in the file before the included

C Code Example eC.2 USING #define TO DECLARE CONSTANTS

// Convert inches to centimeters

#include <stdio.h>

#define INCH2CM 2.54

int main(void) {

float inch = 5.5; // 5.5 inches

float cm;

cm = inch * INCH2CM;

printf("%f inches = %f cm\n", inch, cm);

}

Console Output

5.500000 inches = 13.970000 cm

Globally defined constantseradicate magic numbers froma program. A magic number isa constant that shows up in aprogram without a name. Thepresence of magic numbers in aprogram often introduces trickybugs – for example, when thenumber is changed in onelocation but not another.

Number constants in C defaultto decimal but can also behexadecimal (prefix "0x") oroctal (prefix "0"). Binaryconstants are not defined inC99 but are supported bysome compilers (prefix "0b").For example, the followingassignments are equivalent:

char x = 37;char x = 0x25;char x = 045;

541.e6 APPENDIX C

Page 7: Digital Design and Computer Architecture: ARM® Edition

functions, variables, or identifiers are needed, they are conventionallylocated at the top of a C file.

Programmer-created header files can also be included by using quota-tion marks (" ") around the file name instead of brackets (< >). For exam-ple, a user-created header file called myfunctions.h would be includedusing the following line.

#include "myfunctions.h"

At compile time, files specified in brackets are searched for in systemdirectories. Files specified in quotes are searched for in the same localdirectory where the C file is found. If the user-created header file islocated in a different directory, the path of the file relative to the currentdirectory must be included.

SUMMARY▶ Comments: C provides single-line comments (//) and multi-line com-

ments (/* */).

▶ #define NAME val: the #define directive allows an identifier (NAME)to be used throughout the program. Before compilation, all instancesof NAME are replaced with val.

▶ #include: #include allows common functions to be used in a program.For built-in libraries, include the following line at the top of the code:#include <library.h> To include a user-defined header file, the namemust be in quotes, listing the path relative to the current directory asneeded: i.e., #include "other/myFuncs.h".

C.4 VARIABLES

Variables in C programs have a type, name, value, and memory location.A variable declaration states the type and name of the variable. For exam-ple, the following declaration states that the variable is of type char(which is a 1-byte type), and that the variable name is x. The compilerdecides where to place this 1-byte variable in memory.

char x;

C views memory as a group of consecutive bytes, where each byte of mem-ory is assigned a unique number indicating its location or address, asshown in Figure eC.1. A variable occupies one or more bytes of memory,and the address of multiple-byte variables is indicated by the lowest num-bered byte. The type of a variable indicates whether to interpret the byte(s)as an integer, floating point number, or other type. The rest of this sectiondescribes C’s primitive data types, the declaration of global and local vari-ables, and the initialization of variables.

Variable names are casesensitive and can be of yourchoosing. However, the namemay not be any of C’s reservedwords (i.e., int, while, etc.),may not start with a number(i.e., int 1x; is not a validdeclaration), and may notinclude special characters suchas \, *, ?, or -. Underscores(_) are allowed.

C.4 Variables 541.e7

Page 8: Digital Design and Computer Architecture: ARM® Edition

C . 4 . 1 Primitive Data Types

C has a number of primitive, or built-in, data types available. They can bebroadly characterized as integers, floating-point variables, and characters.An integer represents a two’s complement or unsigned number within afinite range. A floating-point variable uses IEEE floating point representa-tion to describe real numbers with a finite range and precision. A charac-ter can be viewed as either an ASCII value or an 8-bit integer.1 Table eC.2lists the size and range of each primitive type. Integers may be 16, 32,or 64 bits. They use two’s complement unless qualified as unsigned.

Table eC.2 Primitive data types and sizes

Type Size (bits) Minimum Maximum

char 8 −2−7 = −128 27 − 1 = 127

unsigned char 8 0 28 − 1 = 255

short 16 −215 = −32,768 215 − 1 = 32,767

unsigned short 16 0 216 − 1 = 65,535

long 32 −231 = −2,147,483,648 231 − 1 = 2,147,483,647

unsigned long 32 0 232 − 1 = 4,294,967,295

long long 64 −263 263 − 1

unsigned long 64 0 264 − 1

int machine-dependent

unsigned int machine-dependent

float 32 ±2−126 ±2127

double 64 ±2−1023 ±21022

Memory

Address(Byte #)

Data1 byte

10

32

.4

.

.

Figure eC.1 C’s view of memory

1 Technically, the C99 standard defines a character as “a bit representation that fits in abyte,” without requiring a byte to be 8 bits. However, current systems define a byte as 8 bits.

541.e8 APPENDIX C

Page 9: Digital Design and Computer Architecture: ARM® Edition

The scope of a variable is thecontext in which it can beused. For example, for a localvariable, its scope is thefunction in which it isdeclared. It is out of scopeeverywhere else.

The machine-dependentnature of the int data type isa blessing and a curse. On thebright side, it matches thenative word size of theprocessor so it can be fetchedand manipulated efficiently.On the down side, programsusing ints may behavedifferently on differentcomputers. For example, abanking program might storethe number of cents in yourbank account as an int.When compiled on a 64-bitPC, it will have plenty of rangefor even the wealthiestentrepreneur. But if it is portedto a 16-bit microcontroller, itwill overflow for accountsexceeding $327.67, resulting inunhappy and poverty-strickencustomers.

The size of the int type is machine dependent and is generally the nativeword size of the machine. For example, on a 32-bit ARM processor, thesize of an int or unsigned int is 32 bits. Floating point numbers maybe 32- or 64-bit single or double precision. Characters are 8 bits.

C Code Example eC.3 shows the declaration of variables of differenttypes. As shown in Figure eC.2, x requires one byte of data, y requirestwo, and z requires four. The program decides where these bytes are storedin memory, but each type always requires the same amount of data. Forillustration, the addresses of x, y, and z in this example are 1, 2, and 4.Variable names are case-sensitive, so, for example, the variable x and thevariable X are two different variables. (But it would be very confusing touse both in the same program!)

C . 4 . 2 Global and Local Variables

Global and local variables differ in where they are declared and wherethey are visible. A global variable is declared outside of all functions, typi-cally at the top of a program, and can be accessed by all functions. Globalvariables should be used sparingly because they violate the principle ofmodularity, making large programs more difficult to read. However, avariable accessed by many functions can be made global.

A local variable is declared inside a function and can only be used bythat function. Therefore, two functions can have local variables withthe same names without interfering with each other. Local variables aredeclared at the beginning of a function. They cease to exist when the func-tion ends and are recreated when the function is called again. They do notretain their value from one invocation of a function to the next.

C Code Example eC.3 EXAMPLE DATA TYPES

// Examples of several data types and their binary representations

unsigned char x = 42; // x = 00101010

short y = −10; // y = 11111111 11110110

unsigned long z = 0; // z = 00000000 00000000 00000000 00000000

Memory

Address(Byte #)

Data1 byte

10

32

4

Variable Name

x = 42

z = 0

y = -10

56

00101010111101101111111100000000000000000000000000000000

.

..

7

Figure eC.2 Variable storage inmemory for C Code Example eC.3

C.4 Variables 541.e9

Page 10: Digital Design and Computer Architecture: ARM® Edition

C Code Examples eC.4 and eC.5 compare programs using global ver-sus local variables. In C Code Example eC.4, the global variable max canbe accessed by any function. Using a local variable, as shown in C CodeExample eC.5, is the preferred style because it preserves the well-definedinterface of modularity.

C Code Example eC.4 GLOBAL VARIABLES

// Use a global variable to find and print the maximum of 3 numbers

int max; // global variable holding the maximum value

void findMax(int a, int b, int c) {

max = a;

if (b > max) {

if (c > b) max = c;

else max = b;

} else if (c > max) max = c;

}

void printMax(void) {

printf("The maximum number is: %d\n", max);

}

int main(void) {

findMax(4, 3, 7);

printMax();

}

C Code Example eC.5 LOCAL VARIABLES

// Use local variables to find and print the maximum of 3 numbers

int getMax(int a, int b, int c) {

int result = a; // local variable holding the maximum value

if (b > result) {

if (c > b) result = c;

else result = b;

} else if (c > result) result = c;

return result;

}

void printMax(int m) {

printf("The maximum number is: %d\n", m);

}

int main(void) {

int max;

max = getMax(4, 3, 7);

printMax(max);

}

541.e10 APPENDIX C

Page 11: Digital Design and Computer Architecture: ARM® Edition

C . 4 . 3 Initializing Variables

A variable needs to be initialized – assigned a value – before it is read.When a variable is declared, the correct number of bytes is reserved forthat variable in memory. However, the memory at those locations retainswhatever value it had last time it was used, essentially a random value.Global and local variables can be initialized either when they are declaredor within the body of the program. C Code Example eC.3 shows variablesinitialized at the same time they are declared. C Code Example eC.4 showshow variables are initialized before their use, but after declaration; the glo-bal variable max is initialized by the getMax function before it is read bythe printMax function. Reading from uninitialized variables is a commonprogramming error, and can be tricky to debug.

SUMMARY▶ Variables: Each variable is defined by its data type, name, and memory

location. A variable is declared as datatype name.

▶ Data types: A data type describes the size (number of bytes) andrepresentation (interpretation of the bytes) of a variable. Table eC.2lists C’s built-in data types.

▶ Memory: C views memory as a list of bytes. Memory stores variablesand associates each variable with an address (byte number).

▶ Global variables: Global variables are declared outside of all func-tions and can be accessed anywhere in the program.

▶ Local variables: Local variables are declared within a function andcan be accessed only within that function.

▶ Variable initialization: Each variable must be initialized before it isread. Initialization can happen either at declaration or afterward.

C.5 OPERATORS

The most common type of statement in a C program is an expression,such as

y = a + 3;

An expression involves operators (such as + or *) acting on one or moreoperands, such as variables or constants. C supports the operators shownin Table eC.3, listed by category and in order of decreasing precedence.For example, multiplicative operators take precedence over additive

C.5 Operators 541.e11

Page 12: Digital Design and Computer Architecture: ARM® Edition

Table eC.3 Operators listed by decreasing precedence

Category Operator Description Example

Unary ++ post-increment a++; // a = a+1

− − post-decrement x--; // x = x−1

& memory address of a variable x = &y; // x = the memory// address of y

~ bitwise NOT z = ~a;

! Boolean NOT !x

− negation y = -a;

++ pre-increment ++a; // a = a+1

− − pre-decrement --x; // x = x−1

(type) casts a variable to (type) x = (int)c; // cast c to an// int and assign it to x

sizeof() size of a variable or type in bytes long int y;x = sizeof(y); // x = 4

Multiplicative * multiplication y = x * 12;

/ division z = 9 / 3; // z = 3

% modulo z = 5 % 2; // z = 1

Additive + addition y = a + 2;

− subtraction y = a - 2;

Bitwise Shift << bitshift left z = 5 << 2; // z = 0b00010100

>> bitshift right x = 9 >> 3; // x = 0b00000001

Relational == equals y == 2

!= not equals x != 7

< less than y < 12

> greater than val > max

<= less than or equal z <= 2

>= greater than or equal y >= 10

(continued)

541.e12 APPENDIX C

Page 13: Digital Design and Computer Architecture: ARM® Edition

operators. Within the same category, operators are evaluated in the orderthat they appear in the program.

Unary operators, also called monadic operators, have a single operand.Ternary operators have three operands, and all others have two. Theternary operator (from the Latin ternarius meaning consisting of three)chooses the second or third operand depending on whether the firstvalue is TRUE (nonzero) or FALSE (zero), respectively. C Code ExampleeC.6 shows how to compute y = max(a,b) using the ternary operator,along with an equivalent but more verbose if/else statement.

Table eC.3 Operators listed by decreasing precedence—Cont’d

Category Operator Description Example

Bitwise & bitwise AND y = a & 15;

^ bitwise XOR y = 2 ^ 3;

| bitwise OR y = a | b;

Logical && Boolean AND x && y

|| Boolean OR x || y

Ternary ? : ternary operator y = x ? a : b; // if x is TRUE,// y=a, else y=b

Assignment = assignment x = 22;

+= addition and assignment y += 3; // y = y + 3

−= subtraction and assignment z −= 10; // z = z – 10

*= multiplication and assignment x *= 4; // x = x * 4

/= division and assignment y /= 10; // y = y / 10

%= modulo and assignment x %= 4; // x = x % 4

>>= bitwise right-shift and assignment x >>= 5; // x = x>>5

<<= bitwise left-shift and assignment x <<= 2; // x = x<<2

&= bitwise AND and assignment y &= 15; // y = y & 15

|= bitwise OR and assignment x |= y; // x = x | y

^= bitwise XOR and assignment x ^= y; // x = x ^ y

C.5 Operators 541.e13

Page 14: Digital Design and Computer Architecture: ARM® Edition

Simple assignment uses the = operator. C code also allows for com-pound assignment, that is, assignment after a simple operation such asaddition (+=) or multiplication (*=). In compound assignments, the vari-able on the left side is both operated on and assigned the result. C CodeExample eC.7 shows these and other C operations. Binary values in thecomments are indicated with the prefix “0b”.

The Truth, the Whole Truth,and Nothing But the TruthC considers a variable tobe TRUE if it is nonzero andFALSE if it is zero. Logical andternary operators, as well ascontrol-flow statements suchas if and while, depend onthe truth of a variable.Relational and logicaloperators produce a resultthat is 1 when TRUE or 0when FALSE.

C Code Example eC.6 (a) TERNARY OPERATOR, AND (b) EQUIVALENTif/else STATEMENT

(a) y = (a > b) ? a : b; // parentheses not necessary, but makes it clearer

(b) if (a > b) y = a;

else y = b;

C Code Example eC.7 OPERATOR EXAMPLES

Expression Result Notes

44 / 14 3 Integer division truncates

44 % 14 2 44 mod 14

0x2C && 0xE //0b101100 && 0b1110 1 Logical AND

0x2C || 0xE //0b101100 || 0b1110 1 Logical OR

0x2C & 0xE //0b101100 & 0b1110 0xC (0b001100) Bitwise AND

0x2C | 0xE //0b101100 | 0b1110 0x2E (0b101110) Bitwise OR

0x2C ^ 0xE //0b101100 ^ 0b1110 0x22 (0b100010) Bitwise XOR

0xE << 2 //0b1110 << 2 0x38 (0b111000) Left shift by 2

0x2C >> 3 //0b101100 >> 3 0x5 (0b101) Right shift by 3

x = 14;x += 2;

x=16

y = 0x2C; // y = 0b101100y &= 0xF; // y &= 0b1111

y=0xC (0b001100)

x = 14; y = 44;y = y + x++;

x=15, y=58 Increment x after using it

x = 14; y = 44;y = y + ++x;

x=15, y=59 Increment x before using it

541.e14 APPENDIX C

Page 15: Digital Design and Computer Architecture: ARM® Edition

C.6 FUNCTION CALLS

Modularity is key to good programming. A large program is divided intosmaller parts called functions that, similar to hardware modules, havewell-defined inputs, outputs, and behavior. C Code Example eC.8 showsthe sum3 function. The function declaration begins with the return type,int, followed by the name, sum3, and the inputs enclosed within parentheses(int a, int b, int c). Curly braces {} enclose the body of the function,whichmay contain zero or more statements. The return statement indicatesthe value that the function should return to its caller; this can be viewed asthe output of the function. A function can only return a single value.

After the following call to sum3, y holds the value 42.

int y = sum3(10, 15, 17);

Although a function may have inputs and outputs, neither is required.C Code Example eC.9 shows a function with no inputs or outputs. Thekeyword void before the function name indicates that nothing isreturned. void between the parentheses indicates that the function hasno input arguments.

A function must be declared in the code before it is called. This maybe done by placing the called function earlier in the file. For this reason,main is often placed at the end of the C file after all the functions itcalls. Alternatively, a function prototype can be placed in the programbefore the function is defined. The function prototype is the first line of

C Code Example eC.8 sum3 FUNCTION

// Return the sum of the three input variables

int sum3(int a, int b, int c) {

int result = a + b + c;

return result;

}

C Code Example eC.9 FUNCTION printPrompt WITH NO INPUTS OROUTPUTS

// Print a prompt to the console

void printPrompt(void)

{

printf("Please enter a number from 1-3:\n");

}

Nothing between theparentheses also indicates noinput arguments. So, in this casewe could have written:

void printPrompt()

C.6 Function Calls 541.e15

Page 16: Digital Design and Computer Architecture: ARM® Edition

the function, declaring the return type, function name, and functioninputs. For example, the function prototypes for the functions in C CodeExamples eC.8 and eC.9 are:

int sum3(int a, int b, int c);void printPrompt(void);

C Code Example eC.10 shows how function prototypes are used. Eventhough the functions themselves are after main, the function prototypesat the top of the file allow them to be used in main.

The main function is always declared to return an int, which conveys tothe operating system the reason for program termination. A zero indicatesnormal completion, while a nonzero value signals an error condition. Ifmain reaches the end without encountering a return statement, it willautomatically return 0. Most operating systems do not automaticallyinform the user of the value returned by the program.

C.7 CONTROL-FLOW STATEMENTS

C provides control-flow statements for conditionals and loops. Condi-tionals execute a statement only if a condition is met. A loop repeatedlyexecutes a statement as long as a condition is met.

C Code Example eC.10 FUNCTION PROTOTYPES

#include <stdio.h>

// function prototypes

int sum3(int a, int b, int c);

void printPrompt(void);

int main(void)

{

int y = sum3(10, 15, 20);

printf("sum3 result: %d\n", y);

printPrompt();

}

int sum3(int a, int b, int c) {

int result = a+b+c;

return result;

}

void printPrompt(void) {

printf("Please enter a number from 1-3:\n");

}

Console Output

sum3 result: 45

Please enter a number from 1-3:

As with variable names,function names are casesensitive, cannot be any ofC’s reserved words, may notcontain special characters(except underscore _), andcannot start with a number.Typically function namesinclude a verb to indicatewhat they do.

Be consistent in how youcapitalize your function andvariable names so you don’thave to constantly look upthe correct capitalization.Two common styles are tocamelCase, in which the initialletter of each word after thefirst is capitalized like thehumps of a camel (e.g.,printPrompt), or to useunderscores between words(e.g., print_prompt). We haveunscientifically observed thatreaching for the underscorekey exacerbates carpal tunnelsyndrome (my pinky fingertwinges just thinking aboutthe underscore!) and henceprefer camelCase. But themost important thing is tobe consistent in style withinyour organization.

With careful ordering offunctions, prototypes may beunnecessary. However, theyare unavoidable in certaincases, such as when functionf1 calls f2 and f2 calls f1. It isgood style to place prototypesfor all of a program’sfunctions near the beginningof the C file or in a header file.

541.e16 APPENDIX C

Page 17: Digital Design and Computer Architecture: ARM® Edition

Curly braces, {}, are usedto group one or morestatements into a compoundstatement or block.

C . 7 . 1 Conditional Statements

if, if/else, and switch/case statements are conditional statementscommonly used in high-level languages including C.

if StatementsAn if statement executes the statement immediately following it when theexpression in parentheses is TRUE (i.e., nonzero). The general format is:

if (expression)statement

C Code Example eC.11 shows how to use an if statement in C. When thevariable aintBroke is equal to 1, the variable dontFix is set to 1. A blockof multiple statements can be executed by placing curly braces {} aroundthe statements, as shown in C Code Example eC.12.

if/else Statementsif/else statements execute one of two statements depending on a condi-tion, as shown below. When the expression in the if statement isTRUE, statement1 is executed. Otherwise, statement2 is executed.

if (expression)statement1

elsestatement2

C Code Example eC.6(b) gives an example if/else statement in C.The code sets y equal to a if a is greater than b; otherwise y = b.

C Code Example eC.12 if STATEMENT WITH A BLOCK OF CODE

// If amt >= $2, prompt user and dispense candy

if (amt >= 2) {

printf("Select candy.\n");

dispenseCandy = 1;

}

C Code Example eC.11 if STATEMENT

int dontFix = 0;

if (aintBroke == 1)

dontFix = 1;

C.7 Control-Flow Statements 541.e17

Page 18: Digital Design and Computer Architecture: ARM® Edition

switch/case Statementsswitch/case statements execute one of several statements depending onthe conditions, as shown in the general format below.

switch (variable) {case (expression1): statement1 break;case (expression2): statement2 break;case (expression3): statement3 break;default: statement4

}

For example, if variable is equal to expression2, execution con-tinues at statement2 until the keyword break is reached, at which pointit exits the switch/case statement. If no conditions are met, the defaultexecutes.

If the keyword break is omitted, execution begins at the point wherethe condition is TRUE and then falls through to execute the remainingcases below it. This is usually not what you want and is a common erroramong beginning C programmers.

C Code Example eC.13 shows a switch/case statement that, depend-ing on the variable option, determines the amount of money amt to be dis-bursed. A switch/case statement is equivalent to a series of nested if/else statements, as shown by the equivalent code in C Code Example eC.14.

C Code Example eC.14 NESTED if/else STATEMENT

// Assign amt depending on the value of option

if (option == 1) amt = 100;

else if (option == 2) amt = 50;

else if (option == 3) amt = 20;

else if (option == 4) amt = 10;

else printf("Error: unknown option.\n");

C Code Example eC.13 switch/case STATEMENT

// Assign amt depending on the value of option

switch (option) {

case 1: amt = 100; break;

case 2: amt = 50; break;

case 3: amt = 20; break;

case 4: amt = 10; break;

default: printf("Error: unknown option.\n");

}

541.e18 APPENDIX C

Page 19: Digital Design and Computer Architecture: ARM® Edition

C . 7 . 2 Loops

while, do/while, and for loops are common loop constructs used inmany high-level languages including C. These loops repeatedly executea statement as long as a condition is satisfied.

while Loopswhile loops repeatedly execute a statement until a condition is not met, asshown in the general format below.

while (condition)statement

The while loop in C Code Example eC.15 computes the factorial of 9 =9 × 8 × 7 × … × 1. Note that the condition is checked before executing thestatement. In this example, the statement is a compound statement or block,so curly braces are required.

do/while Loopsdo/while loops are like while loops but the condition is checked onlyafter the statement is executed once. The general format is shown below.The condition is followed by a semi-colon.

dostatement

while (condition);

The do/while loop in C Code Example eC.16 queries a user to guess a num-ber. The program checks the condition (if the user’s number is equal to thecorrect number) only after the body of the do/while loop executes once. Thisconstruct is useful when, as in this case, somethingmust be done (for example,the guess retrieved from the user) before the condition is checked.

C Code Example eC.15 while LOOP

// Compute 9! (the factorial of 9)

int i = 1, fact = 1;

// multiply the numbers from 1 to 9

while (i < 10) { // while loops check the condition first

fact *= i;

i++;

}

C Code Example eC.16 do/while LOOP

// Query user to guess a number and check it against the correct number.

#define MAXGUESSES 3

#define CORRECTNUM 7

int guess, numGuesses = 0;

C.7 Control-Flow Statements 541.e19

Page 20: Digital Design and Computer Architecture: ARM® Edition

for Loopsfor loops, like while and do/while loops, repeatedly execute a statementuntil a condition is not satisfied. However, for loops add support for aloop variable, which typically keeps track of the number of loop executions.The general format of the for loop is

for (initialization; condition; loop operation)statement

The initialization code executes only once, before the for loopbegins. The condition is tested at the beginning of each iteration of theloop. If the condition is not TRUE, the loop exits. The loop operationexecutes at the end of each iteration. C Code Example eC.17 shows thefactorial of 9 computed using a for loop.

Whereas the while and do/while loops in C Code Examples eC.15 andeC.16 include code for incrementing and checking the loop variable i andnumGuesses, respectively, the for loop incorporates those statements intoits format. A for loop could be expressed equivalently, but lessconveniently, as

initialization;while (condition) {

statementloop operation;

}

do {

printf("Guess a number between 0 and 9. You have %d more guesses.\n",

(MAXGUESSES-numGuesses));

scanf("%d", &guess); // read user input

numGuesses++;

} while ( (numGuesses < MAXGUESSES) & (guess != CORRECTNUM) );

// do loop checks the condition after the first iteration

if (guess == CORRECTNUM)

printf("You guessed the correct number!\n");

C Code Example eC.17 for LOOP

// Compute 9!

int i; // loop variable

int fact = 1;

for (i=1; i<10; i++)

fact *= i;

541.e20 APPENDIX C

Page 21: Digital Design and Computer Architecture: ARM® Edition

SUMMARY▶ Control-flow statements: C provides control-flow statements for con-

ditional statements and loops.

▶ Conditional statements: Conditional statements execute a statementwhen a condition is TRUE. C includes the following conditionalstatements: if, if/else, and switch/case.

▶ Loops: Loops repeatedly execute a statement until a condition isFALSE. C provides while, do/while, and for loops.

C.8 MORE DATA TYPES

Beyond various sizes of integers and floating-point numbers, C includesother special data types including pointers, arrays, strings, and structures.These data types are introduced in this section along with dynamic mem-ory allocation.

C . 8 . 1 Pointers

A pointer is the address of a variable. C Code Example eC.18 shows how touse pointers. salary1 and salary2 are variables that can contain integers,and ptr is a variable that can hold the address of an integer. The compilerwill assign arbitrary locations in RAM for these variables depending on theruntime environment. For the sake of concreteness, suppose this program iscompiled on a 32-bit system with salary1 at addresses 0x70-73, salary2at addresses 0x74-77, and ptr at 0x78-7B. Figure eC.3 shows memory andits contents after the program is executed.

In a variable declaration, a star (*) before a variable name indicates thatthe variable is a pointer to the declared type. In using a pointer variable,the * operator dereferences a pointer, returning the value stored at the

Memory

Address(Byte #)

Data Variable Name

salary1

ptr

salary2

..

.

67500

68500

0x70

Memory

Address(Byte #)

Data Variable Name

salary1

ptr

salary2

..

.

0x070xAC

0x000x01

0x940x0B0x01

0x700x00

0x000x00

0x00

(a) (b)

0x710x70

0x730x72

0x740x750x76

0x780x77

0x7A0x79

0x7B

0x710x70

0x730x72

0x740x750x76

0x780x77

0x7A0x79

0x7B

Figure eC.3 Contents of memoryafter C Code Example eC.18executes shown (a) by value and(b) by byte using little-endianmemory

C.8 More Data Types 541.21

Page 22: Digital Design and Computer Architecture: ARM® Edition

indicated memory address contained in the pointer. The & operator is pro-nounced “address of,” and it produces the memory address of the variablebeing referenced.

Pointers are particularly useful when a function needs to modify a vari-able, instead of just returning a value. Because functions can’t modify their

inputs directly, a function can make the input a pointer to the variable. Thisis called passing an input variable by reference instead of by value, asshown in prior examples. C Code Example eC.19 gives an example of pas-sing x by reference so that quadruple can modify the variable directly.

A pointer to address 0 is called a null pointer and indicates that the pointer isnot actually pointing to meaningful data. It is written as NULL in a program.

Dereferencing a pointer toa non-existent memorylocation or an address outsideof the range accessible by theprogram will usually cause aprogram to crash. The crashis often called a segmentationfault. C Code Example eC.18 POINTERS

// Example pointer manipulations

int salary1, salary2; // 32-bit numbers

int *ptr; // a pointer specifying the address of an int variable

salary1 = 67500; // salary1 = $67,500 = 0x000107AC

ptr = &salary1; // ptr = 0x0070, the address of salary1

salary2 = *ptr + 1000; /* dereference ptr to give the contents of address 70 = $67,500,

then add $1,000 and set salary2 to $68,500 */

C Code Example eC.19 PASSING AN INPUT VARIABLE BY REFERENCE

// Quadruple the value pointed to by a

#include <stdio.h>

void quadruple(int *a)

{

*a = *a * 4;

}

int main(void)

{

int x = 5;

printf("x before: %d\n", x);

quadruple(&x);

printf("x after: %d\n", x);

return 0;

}

Console Output

x before: 5

x after: 20

541.e22 APPENDIX C

Page 23: Digital Design and Computer Architecture: ARM® Edition

C . 8 . 2 Arrays

An array is a group of similar variables stored in consecutive addresses inmemory. The elements are numbered from 0 to N−1, where N is thelength of the array. C Code Example eC.20 declares an array variablecalled scores that holds the final exam scores for three students. Memoryspace is reserved for three longs, that is, 3 × 4 = 12 bytes. Suppose thescores array starts at address 0x40. The address of the 1st element(i.e., scores[0]) is 0x40, the 2nd element is 0x44, and the 3rd elementis 0x48, as shown in Figure eC.4. In C, the array variable, in this casescores, is a pointer to the 1st element. It is the programmer’s responsibil-ity not to access elements beyond the end of the array. C has no internalbounds checking, so a program that writes beyond the end of an arraywill compile fine but may stomp on other parts of memory when it runs.

The elements of an array can be initialized either at declaration usingcurly braces {}, as shown in C Code Example eC.21, or individually in thebody of the code, as shown in C Code Example eC.22. Each element of anarray is accessed using brackets []. The contents of memory containing thearray are shown in Figure eC.4. Array initialization using curly braces{} canonly be performed at declaration, and not afterward. for loops are commonlyused to assign and read array data, as shown in C Code Example eC.23.

C Code Example eC.21 ARRAY INITIALIZATIONATDECLARATIONUSING { }

long scores[3]={93, 81, 97}; // scores[0]=93; scores[1]=81; scores[2]=97;

C Code Example eC.20 ARRAY DECLARATION

long scores[3]; // array of three 4-byte numbers

Memory

Address(Byte #)

Data Variable Name

scores[0]

scores[2]

scores[1]

..

.

0x410x40

0x430x42

0x440x450x46

0x480x47

0x4A0x49

0x4B

93

81

97

Memory

Address(Byte #)

Data Variable Name

..

.

0x410x40

0x430x42

0x440x450x46

0x480x47

0x4A0x49

0x4B

0x000x5D

0x000x00

0x510x000x00

0x610x00

0x000x00

0x00

scores[0]

scores[2]

scores[1]

Figure eC.4 scores arraystored in memory

C.8 More Data Types 541.e23

Page 24: Digital Design and Computer Architecture: ARM® Edition

When an array is declared, the length must be constant so that the compilercan allocate the proper amount of memory. However, when the array ispassed to a function as an input argument, the length need not be definedbecause the function only needs to know the address of the beginning ofthe array. C Code Example eC.24 shows how an array is passed to a func-tion. The input argument arr is simply the address of the 1st element of anarray. Often the number of elements in an array is also passed as an inputargument. In a function, an input argument of type int[] indicates that itis an array of integers. Arrays of any type may be passed to a function.

C Code Example eC.23 ARRAY INITIALIZATION USING A for LOOP

// User enters 3 student scores into an array

long scores[3];

int i, entered;

printf("Please enter the student's 3 scores.\n");

for (i=0; i<3; i++) {

printf("Enter a score and press enter.\n");

scanf("%d", &entered);

scores[i] = entered;

}

printf("Scores: %d %d %d\n", scores[0], scores[1], scores[2]);

C Code Example eC.24 PASSING AN ARRAY AS AN INPUT ARGUMENT

// Initialize a 5-element array, compute the mean, and print the result.

#include <stdio.h>

// Returns the mean value of an array (arr) of length len

float getMean(int arr[], int len) {

int i;

float mean, total = 0;

for (i=0; i < len; i++)

total += arr[i];

mean = total / len;

return mean;

}

C Code Example eC.22 ARRAY INITIALIZATION USING ASSIGNMENT

long scores[3];

scores[0] = 93;

scores[1] = 81;

scores[2] = 97;

541.e24 APPENDIX C

Page 25: Digital Design and Computer Architecture: ARM® Edition

An array argument is equivalent to a pointer to the beginning of thearray. Thus, getMean could also have been declared as

float getMean(int *arr, int len);

Although functionally equivalent, datatype[] is the preferredmethod for passing arrays as input arguments because it more clearlyindicates that the argument is an array.

A function is limited to a single output, i.e., return variable. However,by receiving an array as an input argument, a function can essentiallyoutput more than a single value by changing the array itself. C CodeExample eC.25 sorts an array from lowest to highest and leaves the resultin the same array. The three function prototypes below are equivalent.The length of an array in a function declaration (i.e., int vals[100]) isignored.

void sort(int *vals, int len);void sort(int vals[], int len);void sort(int vals[100], int len);

int main(void) {

int data[4] = {78, 14, 99, 27};

float avg;

avg = getMean(data, 4);

printf("The average value is: %f.\n", avg);

}

Console Output

The average value is: 54.500000.

C Code Example eC.25 PASSING AN ARRAY AND ITS LENGTH AS INPUTS

// Sort the elements of the array vals of length len from lowest to highest

void sort(int vals[], int len)

{

int i, j, temp;

for (i=0; i<len; i++) {

for (j=i+1; j<len; j++) {

if (vals[i] > vals[j]) {

temp = vals[i];

vals[i] = vals[j];

vals[j] = temp;

}

}

}

}

C.8 More Data Types 541.e25

Page 26: Digital Design and Computer Architecture: ARM® Edition

Arrays may have multiple dimensions. C Code Example eC.26 uses atwo-dimensional array to store the grades across eight problem sets forten students. Recall that initialization of array values using {} is onlyallowed at declaration.

C Code Example eC.27 shows some functions that operate on the 2-Dgrades array from C Code Example eC.26. Multi-dimensional arraysused as input arguments to a function must define all but the first dimen-sion. Thus, the following two function prototypes are acceptable:

void print2dArray(int arr[10][8]);void print2dArray(int arr[][8]);

C Code Example eC.26 TWO-DIMENSIONAL ARRAY INITIALIZATION

// Initialize 2-D array at declaration

int grades[10][8] = { {100, 107, 99, 101, 100, 104, 109, 117},

{103, 101, 94, 101, 102, 106, 105, 110},

{101, 102, 92, 101, 100, 107, 109, 110},

{114, 106, 95, 101, 100, 102, 102, 100},

{98, 105, 97, 101, 103, 104, 109, 109},

{105, 103, 99, 101, 105, 104, 101, 105},

{103, 101, 100, 101, 108, 105, 109, 100},

{100, 102, 102, 101, 102, 101, 105, 102},

{102, 106, 110, 101, 100, 102, 120, 103},

{99, 107, 98, 101, 109, 104, 110, 108} };

C Code Example eC.27 OPERATING ON MULTI-DIMENSIONAL ARRAYS

#include <stdio.h>

// Print the contents of a 10 × 8 array

void print2dArray(int arr[10][8])

{

int i, j;

for (i=0; i<10; i++) { // for each of the 10 students

printf("Row %d\n", i);

for (j=0; j<8; j++) {

printf("%d ", arr[i][j]); // print scores for all 8 problem sets

}

printf("\n");

}

}

// Calculate the mean score of a 10 × 8 array

float getMean(int arr[10][8])

{

int i, j;

float mean, total = 0;

// get the mean value across a 2D array

for (i=0; i<10; i++) {

541.e26 APPENDIX C

Page 27: Digital Design and Computer Architecture: ARM® Edition

The term “carriage return”originates from typewritersthat required the carriage, thecontraption that holds thepaper, to move to the right inorder to allow typing to beginat the left side of the page.A carriage return lever, shownon the left in the figure below,is pressed so that the carriagewould both move to the rightand advance the paper byone line, called a line feed.

A Remington electric typewriterused by Winston Churchill.(http://cwr.iwm.org.uk/server/show/conMediaFile.71979)

Note that because an array is represented by a pointer to the initial element,C cannot copy or compare arrays using the = or == operators. Instead, youmust use a loop to copy or compare each element one at a time.

C . 8 . 3 Characters

A character (char) is an 8-bit variable. It can be viewed either as a two’scomplement number between −128 and 127 or as an ASCII code for aletter, digit, or symbol. ASCII characters can be specified as a numeric value(in decimal, hexadecimal, etc.) or as a printable character enclosed in singlequotes. For example, the letter A has the ASCII code 0x41, B=0x42, etc. Thus'A' + 3 is 0x44, or 'D'. Table 6.5 lists the ASCII character encodings, andTable eC.4 lists characters used to indicate formatting or special characters.Formatting codes include carriage return (\r), newline (\n), horizontal tab(\t), and the end of a string (\0). \r is shown for completeness but is rarelyused in C programs. \r returns the carriage (location of typing) to the begin-ning (left) of the line, but any text that was there is overwritten. \n, instead,moves the location of typing to the beginning of a new line.2 The NULLcharacter ('\0') indicates the end of a text string and is discussed nextin Section C.8.4.

for (j=0; j<8; j++) {

total += arr[i][j]; // sum array values

}

}

mean = total/(10*8);

printf("Mean is: %f\n", mean);

return mean;

}

Table eC.4 Special characters

Special Character Hexadecimal Encoding Description

\r 0x0D carriage return

\n 0x0A new line

\t 0x09 tab

\0 0x00 terminates a string

\\ 0x5C backslash

\" 0x22 double quote

\' 0x27 single quote

\a 0x07 bell

2 Windows text files use \r\n to represent end-of-line while UNIX-based systems use \n,which can cause nasty bugs when moving text files between systems.

C.8 More Data Types 541.e27

Page 28: Digital Design and Computer Architecture: ARM® Edition

C strings are called nullterminated or zero terminatedbecause the length isdetermined by looking for azero at the end. In contrast,languages such as Pascal usethe first byte to specify thestring length, up to amaximum of 255 characters.This byte is called the prefixbyte and such strings arecalled P-strings. An advantageof null-terminated strings isthat the length can bearbitrarily great. Anadvantage of P-strings is thatthe length can be determinedimmediately without havingto inspect all of the charactersof the string.

C . 8 . 4 Strings

A string is an array of characters used to store a piece of text of boundedbut variable length. Each character is a byte representing the ASCII codefor that letter, number, or symbol. The size of the array determines themaximum length of the string, but the actual length of the string couldbe shorter. In C, the length of the string is determined by looking forthe null terminator (ASCII value 0x00) at the end of the string.

C Code Example eC.28 shows the declaration of a 10-element char-acter array called greeting that holds the string "Hello!". For concrete-ness, suppose greeting starts at memory address 0x50. Figure eC.5shows the contents of memory from 0x50 to 0x59 holding the string"Hello!" Note that the string only uses the first seven elements of thearray, even though ten elements are allocated in memory.

C Code Example eC.29 shows an alternate declaration of the stringgreeting. The pointer greeting holds the address of the 1st element ofa 7-element array comprised of each of the characters in “Hello!”followed by the null terminator. The code also demonstrates how to printstrings by using the %s format code.

Unlike primitive variables, a string cannot be set equal to another stringusing the equals operator, =. Each element of the character array must beindividually copied from the source string to the target string. This is truefor any array. C Code Example eC.30 copies one string, src, to another,dst. The sizes of the arrays are not needed, because the end of the src stringis indicated by the null terminator. However, dst must be large enough sothat you don’t stomp on other data. strcpy and other string manipulationfunctions are available in C’s built-in libraries (see Section C.9.4).

C Code Example eC.28 STRING DECLARATION

char greeting[10] = "Hello!";

C Code Example eC.29 ALTERNATE STRING DECLARATION

char *greeting = "Hello!";printf("greeting: %s", greeting);

Console Output

greeting: Hello!

C Code Example eC.30 COPYING STRINGS

// Copy the source string, src, to the destination string, dst

void strcpy(char *dst, char *src)

{

541.e28 APPENDIX C

Page 29: Digital Design and Computer Architecture: ARM® Edition

C . 8 . 5 Structures

In C, structures are used to store a collection of data of various types. Thegeneral format of a structure declaration is

struct name {type1 element1;type2 element2;…

};

where struct is a keyword indicating that it is a structure, name is thestructure tag name, and element1 and element2 are members of the struc-ture. A structure may have any number of members. C Code ExampleeC.31 shows how to use a structure to store contact information. The pro-gram then declares a variable c1 of type struct contact.

Memory

Address(Byte #)

Data Variable Name

str

..

.

0x500x4F

0x520x51

0x530x540x55

0x570x56

0x590x58

0x5A

"Hello!"

Memory

Address(Byte #)

Data Variable Name

..

.

0x500x4F

0x520x51

0x530x540x55

0x570x56

0x590x58

0x5A

0x480x650x6C

0x6F0x6C

0x000x21

str

unknown

unknownunknown

Figure eC.5 The string “Hello!”stored in memory

int i = 0;

do {

dst[i] = src[i]; // copy characters one byte at a time

} while (src[i++]); // until the null terminator is found

}

C Code Example eC.31 STRUCTURE DECLARATION

struct contact {

char name[30];

int phone;

float height; // in meters

};

struct contact c1;

C.8 More Data Types 541.e29

Page 30: Digital Design and Computer Architecture: ARM® Edition

Just like built-in C types, you can create arrays of structures and pointersto structures. C Code Example eC.32 creates an array of contacts.

It is common to use pointers to structures. C provides the member accessoperator -> to dereference a pointer to a structure and access a member ofthe structure. C Code Example eC.33 shows an example of declaring apointer to a struct contact, assigning it to point to the 42nd element ofclasslist from C Code Example eC.32, and using the member accessoperator to set a value in that element.

Structures can be passed as function inputs or outputs by value or by refer-ence. Passing by value requires the compiler to copy the entire structure intomemory for the function to access. This can require a large amount of mem-ory and time for a big structure. Passing by reference involves passing apointer to the structure, which is more efficient. The function can alsomodify the structure being pointed to rather than having to return anotherstructure. C Code Example eC.34 shows two versions of the stretch func-tion that makes a contact 2 cm taller. stretchByReference avoidscopying the large structure twice.

C Code Example eC.32 ARRAY OF STRUCTURES

struct contact classlist[200];

classlist[0].phone = 9642025;

C Code Example eC.33 ACCESSING STRUCTURE MEMBERS USINGPOINTERS AND ->

struct contact *cptr;

cptr = &classlist[42];

cptr->height = 1.9; // equivalent to: (*cptr).height = 1.9;

strcpy(c1.name, "Ben Bitdiddle");

c1.phone = 7226993;

c1.height = 1.82;

C Code Example eC.34 PASSING STRUCTURES BY VALUE OR BY NAME

struct contact stretchByValue(struct contact c)

{

c.height += 0.02;

return c;

}

541.e30 APPENDIX C

Page 31: Digital Design and Computer Architecture: ARM® Edition

C . 8 . 6 typedef

C also allows you to define your own names for data types using thetypedef statement. For example, writing struct contact becomestedious when it is often used, so we can define a new type named contactand use it as shown in C Code Example eC.35.

typedef can be used to create a new type occupying the same amount ofmemory as a primitive type. C Code Example eC.36 defines byte and boolas 8-bit types. The byte type may make it clearer that the purpose of pos isto be an 8-bit number rather than an ASCII character. The bool type indi-cates that the 8-bit number is representing TRUE or FALSE. These typesmake a program easier to read than if one simply used char everywhere.

void stretchByReference(struct contact *cptr)

{

cptr->height += 0.02;

}

int main(void)

{

struct contact George;

George.height = 1.4; // poor fellow has been stooped over

George = stretchByValue(George); // stretch for the stars

stretchByReference(&George); // and stretch some more

}

C Code Example eC.35 CREATING A CUSTOM TYPE USING typedef

typedef struct contact {

char name[30];

int phone;

float height; // in meters

} contact; // defines contact as shorthand for "struct contact"

contact c1; // now we can declare the variable as type contact

C Code Example eC.36 typedef byte AND bool

typedef unsigned char byte;

typedef char bool;

#define TRUE 1

#define FALSE 0

byte pos = 0x45;

bool loveC = TRUE;

C.8 More Data Types 541.e31

Page 32: Digital Design and Computer Architecture: ARM® Edition

C Code Example eC.37 illustrates defining a 3-element vector and a3 × 3 matrix type using arrays.

C . 8 . 7 Dynamic Memory Allocation*

In all the examples thus far, variables have been declared statically; that is,their size is known at compile time. This can be problematic for arrays andstrings of variable size because the array must be declared large enough toaccommodate the largest size the program will ever see. An alternative isto dynamically allocate memory at run time when the actual size is known.

The malloc function from stdlib.h allocates a block of memory ofa specified size and returns a pointer to it. If not enough memory is avail-able, it returns a NULL pointer instead. For example, the following codeallocates 10 shorts (10 × 2 = 20 bytes). The sizeof operator returns thesize of a type or variable in bytes.

// dynamically allocate 20 bytes of memoryshort *data = malloc(10*sizeof(short));

C Code Example eC.38 illustrates dynamic allocation and de-allocation.The program accepts a variable number of inputs, stores them in a dynami-cally allocated array, and computes their average. The amount of memorynecessary depends on the number of elements in the array and the size of eachelement. For example, if an int is a 4-byte variable and 10 elements areneeded, 40 bytes are dynamically allocated. The free function de-allocatesthe memory so that it could later be used for other purposes. Failing tode-allocate dynamically allocated data is called a memory leak and shouldbe avoided.

C Code Example eC.37 typedef vector AND matrix

typedef double vector[3];

typedef double matrix[3][3];

vector a = {4.5, 2.3, 7.0};

matrix b = {{3.3, 4.7, 9.2}, {2.5, 4, 9}, {3.1, 99.2, 88}};

C Code Example eC.38 DYNAMIC MEMORY ALLOCATION ANDDE-ALLOCATION

// Dynamically allocate and de-allocate an array using malloc and free

#include <stdlib.h>

// Insert getMean function from C Code Example eC.24.

int main(void) {

int len, i;

541.e32 APPENDIX C

Page 33: Digital Design and Computer Architecture: ARM® Edition

C . 8 . 8 Linked Lists*

A linked list is a common data structure used to store a variable numberof elements. Each element in the list is a structure containing one or moredata fields and a link to the next element. The first element in the list iscalled the head. Linked lists illustrate many of the concepts of structures,pointers, and dynamic memory allocation.

C Code Example eC.39 describes a linked list for storing computer useraccounts to accommodate a variable number of users. Each user has a username, a password, a unique user identification number (UID), and a field indi-cating whether they have administrator privileges. Each element of the list is oftype userL, containing all of this user information alongwith a link to the nextelement in the list. A pointer to the head of the list is stored in a global variablecalled users, and is initially set to NULL to indicate that there are no users.

The program defines functions to insert, delete, and find a user and tocount the number of users. The insertUser function allocates space for anew list element and adds it to the head of the list. The deleteUser functionscans through the list until the specified UID is found and then removes thatelement, adjusting the link from the previous element to skip the deletedelement and freeing the memory occupied by the deleted element. ThefindUser function scans through the list until the specified UID is foundand returns a pointer to that element, or NULL if the UID is not found.The numUsers function counts the number of elements in the list.

int *nums;

printf("How many numbers would you like to enter? ");

scanf("%d", &len);

nums = malloc(len*sizeof(int));

if (nums == NULL) printf("ERROR: out of memory.\n");

else {

for (i=0; i<len; i++) {

printf("Enter number: ");

scanf("%d", &nums[i]);

}

printf("The average is %f\n", getMean(nums, len));

}

free(nums);

}

C Code Example eC.39 LINKED LIST

#include <stdlib.h>

#include <string.h>

typedef struct userL {

C.8 More Data Types 541.e33

Page 34: Digital Design and Computer Architecture: ARM® Edition

char uname[80]; // user name

char passwd[80]; // password

int uid; // user identification number

int admin; // 1 indicates administrator privileges

struct userL *next;

} userL;

userL *users = NULL;

void insertUser(char *uname, char *passwd, int uid, int admin) {

userL *newUser;

newUser = malloc(sizeof(userL)); // create space for new user

strcpy(newUser->uname, uname); // copy values into user fields

strcpy(newUser->passwd, passwd);

newUser->uid = uid;

newUser->admin = admin;

newUser->next = users; // insert at start of linked list

users = newUser;

}

void deleteUser(int uid) { // delete first user with given uid

userL *cur = users;

userL *prev = NULL;

while (cur != NULL) {

if (cur->uid == uid) { // found the user to delete

if (prev == NULL) users = cur->next;

else prev->next = cur->next;

free(cur);

return; // done

}

prev = cur; // otherwise, keep scanning through list

cur = cur->next;

}

}

userL *findUser(int uid) {

userL *cur = users;

while (cur != NULL) {

if (cur->uid == uid) return cur;

else cur = cur->next;

}

return NULL;

}

int numUsers(void) {

userL *cur = users;

int count = 0;

while (cur != NULL) {

count++;

cur = cur->next;

}

return count;

}

541.e34 APPENDIX C

Page 35: Digital Design and Computer Architecture: ARM® Edition

SUMMARY▶ Pointers: A pointer holds the address of a variable.

▶ Arrays: An array is a list of similar elements declared using squarebrackets [].

▶ Characters: char types can hold small integers or special codes forrepresenting text or symbols.

▶ Strings: A string is an array of characters ending with the null termi-nator 0x00.

▶ Structures: A structure stores a collection of related variables.

▶ Dynamic memory allocation: malloc is a built-in functions for allo-cating memory as the program runs. free de-allocates the memoryafter use.

▶ Linked Lists: A linked list is a common data structure for storing avariable number of elements.

C.9 STANDARD LIBRARIES

Programmers commonly use a variety of standard functions, such asprinting and trigonometric operations. To save each programmer fromhaving to write these functions from scratch, C provides libraries of fre-quently used functions. Each library has a header file and an associatedobject file, which is a partially compiled C file. The header file holds vari-able declarations, defined types, and function prototypes. The object filecontains the functions themselves and is linked at compile-time to createthe executable. Because the library function calls are already compiledinto an object file, compile time is reduced. Table eC.5 lists some of themost frequently used C libraries, and each is described briefly below.

C . 9 . 1 stdio

The standard input/output library stdio.h contains commands for print-ing to a console, reading keyboard input, and reading and writing files. Touse these functions, the library must be included at the top of the C file:

#include <stdio.h>

printfThe print formatted statement printf displays text to the console. Itsrequired input argument is a string enclosed in quotes "". The string containstext and optional commands to print variables. Variables to be printed arelisted after the string and are printed using format codes shown inTable eC.6. C Code Example eC.40 gives a simple example of printf.

C.9 Standard Libraries 541.e35

Page 36: Digital Design and Computer Architecture: ARM® Edition

Table eC.5 Frequently used C libraries

C Library Header File Description

stdio.h Standard input/output library. Includes functionsfor printing or reading to/from the screen or a file(printf, fprintf and scanf, fscanf) and to openand close files (fopen and fclose).

stdlib.h Standard library. Includes functions for randomnumber generation (rand and srand), fordynamically allocating or freeing memory (mallocand free), terminating the program early (exit),and for conversion between strings and numbers(atoi, atol, and atof).

math.h Math library. Includes standard math functionssuch as sin, cos, asin, acos, sqrt, log, log10,exp, floor, and ceil.

string.h String library. Includes functions to compare, copy,concatenate, and determine the length of strings.

Table eC.6 printf format codes for printing variables

Code Format

%d Decimal

%u Unsigned decimal

%x Hexadecimal

%o Octal

%f Floating point number (float or double)

%e Floating point number (float or double) in scientific notation(e.g., 1.56e7)

%c Character (char)

%s String (null-terminated array of characters)

C Code Example eC.40 PRINTING TO THE CONSOLE USING printf

// Simple print function

#include <stdio.h>

int num = 42;

541.e36 APPENDIX C

Page 37: Digital Design and Computer Architecture: ARM® Edition

Floating point formats (floats and doubles) default to printing six digitsafter the decimal point. To change the precision, replace %f with %w.df,where w is the minimumwidth of the number, and d is the number of decimalplaces to print. Note that the decimal point is included in the width count. InC Code Example eC.41, pi is printed with a total of four characters, two ofwhich are after the decimal point: 3.14. e is printed with a total of eight char-acters, three of which are after the decimal point. Because it only has onedigit before the decimal point, it is padded with three leading spaces to reachthe requested width. c should be printed with five characters, three of whichare after the decimal point. But it is too wide to fit, so the requested width isoverridden while retaining the three digits after the decimal point.

Because % and \ are used in print formatting, to print these charactersthemselves, you must use the special character sequences shown in CCode Example eC.42.

int main(void) {

printf("The answer is %d.\n", num);

}

Console Output:

The answer is 42.

C Code Example eC.41 FLOATING POINT NUMBER FORMATS FORPRINTING

// Print floating point numbers with different formats

float pi = 3.14159, e = 2.7182, c = 2.998e8;

printf("pi = %4.2f\ne = %8.3f\nc = %5.3f\n", pi, e, c);

Console Output:

pi = 3.14

e = 2.718

c = 299800000.000

C Code Example eC.42 PRINTING % AND \ USING printf

// How to print % and \ to the console

printf("Here are some special characters: %% \\ \n");

Console Output:

Here are some special characters: % \

C.9 Standard Libraries 541.e37

Page 38: Digital Design and Computer Architecture: ARM® Edition

scanfThe scanf function reads text typed on the keyboard. It uses formatcodes in the same way as printf. C Code Example eC.43 shows howto use scanf. When the scanf function is encountered, the program waitsuntil the user types a value before continuing execution. The arguments toscanf are a string indicating one or more format codes and pointers tothe variables where the results should be stored.

File ManipulationMany programs need to read and write files, either to manipulate dataalready stored in a file or to log large amounts of information. In C, thefile must first be opened with the fopen function. It can then be read or writ-ten with fscanf or fprintf in a way analogous to reading and writing tothe console. Finally, it should be closed with the fclose command.

The fopen function takes as arguments the file name and a print mode. Itreturns a file pointer of type FILE*. If fopen is unable to open the file,it returns NULL. This might happen when one tries to read a nonexistent fileor write a file that is already opened by another program. The modes are:

"w": Write to a file. If the file exists, it is overwritten.

"r": Read from a file.

"a": Append to the end of an existing file. If the file doesn’t exist, it iscreated.

C Code Example eC.43 READING USER INPUT FROM THE KEYBOARD WITHscanf

// Read variables from the command line

#include <stdio.h>

int main(void)

{

int a;

char str[80];

float f;

printf("Enter an integer.\n");

scanf("%d", &a);

printf("Enter a floating point number.\n");

scanf("%f", &f);

printf("Enter a string.\n");

scanf("%s", str); // note no & needed: str is a pointer

}

541.e38 APPENDIX C

Page 39: Digital Design and Computer Architecture: ARM® Edition

C Code Example eC.44 shows how to open, print to, and close a file.It is good practice to always check if the file was opened successfully andto provide an error message if it was not. The exit function will be dis-cussed in Section C.9.2. The fprintf function is like printf but it alsotakes the file pointer as an input argument to know which file to write.fclose closes the file, ensuring that all of the information is actually writ-ten to disk and freeing up file system resources.

C Code Example eC.45 illustrates reading numbers from a file nameddata.txt using fscanf. The file must first be opened for reading. The pro-gram then uses the feof function to check if it has reached the end of thefile. As long as the program is not at the end, it reads the next number andprints it to the screen. Again, the program closes the file at the end to freeup resources.

C Code Example eC.44 PRINTING TO A FILE USING fprintf

// Write "Testing file write." to result.txt

#include <stdio.h>

#include <stdlib.h>

int main(void) {

FILE *fptr;

if ((fptr = fopen("result.txt", "w")) == NULL) {

printf("Unable to open result.txt for writing.\n");

exit(1); // exit the program indicating unsuccessful execution

}

fprintf(fptr, "Testing file write.\n");

fclose(fptr);

}

C Code Example eC.45 READING INPUT FROM A FILE USING fscanf

#include <stdio.h>

int main(void)

{

FILE *fptr;

int data;

// read in data from input file

if ((fptr = fopen("data.txt", "r")) == NULL) {

printf("Unable to read data.txt\n");

exit(1);

}

It is idiomatic to open a fileand check if the file pointer isNULL in a single line of code, asshown in C Code ExampleeC.44. However, you couldjust as easily separate thefunctionality into two lines:

fptr = fopen(“result.txt”, “w”);if (fptr == NULL)...

C.9 Standard Libraries 541.e39

Page 40: Digital Design and Computer Architecture: ARM® Edition

Other Handy stdio FunctionsThe sprintf function prints characters into a string, and sscanf readsvariables from a string. The fgetc function reads a single character froma file, while fgets reads a complete line into a string.

fscanf is rather limited in its ability to read and parse complex files,so it is often easier to fgets one line at a time and then digest that lineusing sscanf or with a loop that inspects characters one at a time usingfgetc.

C . 9 . 2 stdlib

The standard library stdlib.h provides general purpose functionsincluding random number generation (rand and srand), dynamic mem-ory allocation (malloc and free, already discussed in Section C.8.7),exiting the program early (exit), and number format conversions. Touse these functions, add the following line at the top of the C file.

#include <stdlib.h>

rand and srandrand returns a pseudo-random integer. Pseudo-random numbers have thestatistics of random numbers but follow a deterministic pattern startingwith an initial value called the seed. To convert the number to a particularrange, use the modulo operator (%) as shown in C Code Example eC.46 fora range of 0 to 9. The values x and y will be random but they will be thesame each time this program runs. Sample console output is given belowthe code.

while (!feof(fptr)) { // check that the end of the file hasn't been reached

fscanf(fptr, "%d", &data);

printf("Read data: %d\n", data);

}

fclose(fptr);

}

data.txt

25 32 14 89

Console Output:

Read data: 25

Read data: 32

Read data: 14

Read data: 89

541.e40 APPENDIX C

Page 41: Digital Design and Computer Architecture: ARM® Edition

A programmer creates a different sequence of random numbers each timea program runs by changing the seed. This is done by calling the srandfunction, which takes the seed as its input argument. As shown in CCode Example eC.47, the seed itself must be random, so a typical Cprogram assigns it by calling the time function, that returns the currenttime in seconds.

exitThe exit function terminates a program early. It takes a single argumentthat is returned to the operating system to indicate the reason for termina-tion. 0 indicates normal completion, while nonzero conveys an errorcondition.

Format Conversion: atoi, atol, atofThe standard library provides functions for converting ASCII strings tointegers, long integers, or doubles using atoi, atol, and atof, respec-tively, as shown in C Code Example eC.48. This is particularly useful

C Code Example eC.46 RANDOM NUMBER GENERATION USING rand

#include <stdlib.h>

int x, y;

x = rand(); // x = a random integer

y = rand() % 10; // y = a random number from 0 to 9

printf(“x = %d, y = %d\n”, x, y);

Console Output:

x = 1481765933, y = 3

C Code Example eC.47 SEEDING THE RANDOM NUMBER GENERATORUSING srand

// Produce a different random number each run

#include <stdlib.h>

#include <time.h> // needed to call time()

int main(void)

{

int x;

srand(time(NULL)); // seed the random number generator

x = rand() % 10; // random number from 0 to 9

printf("x = %d\n", x);

}

For historical reasons, thetime function usually returnsthe current time in secondsrelative to January 1, 197000:00 UTC. UTC stands forCoordinated Universal Time,which is the same asGreenwich Mean Time(GMT). This date is just afterthe UNIX operating systemwas created by a group at BellLabs, including Dennis Ritchieand Brian Kernighan, in 1969.Similar to New Year’s Eve parties,some UNIX enthusiasts holdparties to celebrate significantvalues returned by time. Forexample, on February 1, 2009 at23:31:30 UTC, time returned1,234,567,890. In the year 2038,32-bit UNIX clocks will overflowinto the year 1901.

C.9 Standard Libraries 541.e41

Page 42: Digital Design and Computer Architecture: ARM® Edition

when reading in mixed data (a mix of strings and numbers) from a file orwhen processing numeric command line arguments, as described inSection C.10.3.

C . 9 . 3 math

The math library math.h provides commonly used math functions suchas trigonometry functions, square root, and logs. C Code ExampleeC.49 shows how to use some of these functions. To use math functions,place the following line in the C file:

#include <math.h>

C Code Example eC.48 FORMAT CONVERSION

// Convert ASCII strings to ints, longs, and floats

#include <stdlib.h>

int main(void)

{

int x;

long int y;

double z;

x = atoi("42");

y = atol("833");

z = atof("3.822");

printf("x = %d\ty = %d\tz = %f\n", x, y, z);

}

Console Output:

x = 42 y = 833 z = 3.822000

C Code Example eC.49 MATH FUNCTIONS

// Example math functions

#include <stdio.h>

#include <math.h>

int main(void) {

float a, b, c, d, e, f, g, h;

a = cos(0); // 1, note: the input argument is in radians

b = 2 * acos(0); // pi (acos means arc cosine)

c = sqrt(144); // 12

d = exp(2); // e^2 = 7.389056,

e = log(7.389056); // 2 (natural logarithm, base e)

541.e42 APPENDIX C

Page 43: Digital Design and Computer Architecture: ARM® Edition

C . 9 . 4 string

The string library string.h provides commonly used string manipulationfunctions. Key functions include:

// copy src into dst and return dstchar *strcpy(char *dst, char *src);

// concatenate (append) src to the end of dst and return dstchar *strcat(char *dst, char *src);

// compare two strings. Return 0 if equal, nonzero otherwiseint strcmp(char *s1, char *s2);

// return the length of str, not including the null terminationint strlen(char *str);

C.10 COMPILER AND COMMAND LINE OPTIONS

Although we have introduced relatively simple C programs, real-worldprograms can consist of tens or even thousands of C files to enable mod-ularity, readability, and multiple programmers. This section describeshow to compile a program spread across multiple C files and showshow to use compiler options and command line arguments.

C . 1 0 . 1 Compiling Multiple C Source Files

Multiple C files are compiled into a single executable by listing all filenames on the compile line as shown below. Remember that the groupof C files still must contain only one main function, conventionally placedin a file named main.c.

gcc main.c file2.c file3.c

C . 1 0 . 2 Compiler Options

Compiler options allow the programmer to specify such things as outputfile names and formats, optimizations, etc. Compiler options are not

f = log10(1000); // 3 (log base 10)

g = floor(178.567); // 178, rounds to next lowest whole number

h = pow(2, 10); // computes 2 raised to the 10th power

printf("a = %.0f, b = %f, c = %.0f, d = %.0f, e = %.2f, f = %.0f, g = %.2f, h = %.2f\n",

a, b, c, d, e, f, g, h);

}

Console Output:

a = 1, b = 3.141593, c = 12, d = 7, e = 2.00, f = 3, g = 178.00, h = 1024.00

C.10 Compiler and Command Line Options 541.e43

Page 44: Digital Design and Computer Architecture: ARM® Edition

standardized, but Table eC.7 lists ones that are commonly used. Eachoption is typically preceded by a dash (-) on the command line, as shown.For example, the "-o" option allows the programmer to specify an outputfile name other than the a.out default. A plethora of options exist; theycan be viewed by typing gcc --help at the command line.

C . 1 0 . 3 Command Line Arguments

Like other functions, main can also take input variables. However,unlike other functions, these arguments are specified at the commandline. As shown in C Code Example eC.50, argc stands for argumentcount, and it denotes the number of arguments on the commandline. argv stands for argument vector, and it is an array of the stringsfound on the command line. For example, suppose the program inC Code Example eC.50 is compiled into an executable called testargs.When the lines below are typed at the command line, argc has the value4, and the array argv has the values {"./testargs", "arg1", "25","lastarg!"}. Note that the executable name is counted as the 1st

argument. The console output after typing this command is shownbelow C Code Example eC.50.

gcc -o testargs testargs.c./testargs arg1 25 lastarg!

Programs that need numeric arguments may convert the string argumentsto numbers using the functions in stdlib.h.

Table eC.7 Compiler options

Compiler Option Description Example

-o outfile specifies output file name gcc -o hello hello.c

-S create assembly language output file (not executable) gcc -S hello.cthis produces hello.s

-v verbose mode – prints the compiler results andprocesses as compilation completes

gcc -v hello.c

-Olevel specify the optimization level (level is typically 0through 3), producing faster and/or smaller code at theexpense of longer compile time

gcc -O3 hello.c

--version list the version of the compiler gcc –version

--help list all command line options gcc --help

-Wall print all warnings gcc -Wall hello.c

541.e44 APPENDIX C

Page 45: Digital Design and Computer Architecture: ARM® Edition

C.11 COMMON MISTAKES

As with any programming language, you are almost certain to makeerrors while you write nontrivial C programs. Below are descriptions ofsome common mistakes made when programming in C. Some of theseerrors are particularly troubling because they compile but do not functionas the programmer intended.

C Code Example eC.50 COMMAND LINE ARGUMENTS

// Print command line arguments

#include <stdio.h>

int main(int argc, char *argv[])

{

int i;

for (i=0; i<argc; i++)

printf("argv[%d] = %s\n", i, argv[i]);

}

Console Output:

argv[0] = ./testargs

argv[1] = arg1

argv[2] = 25

argv[3] = lastarg!

C Code Mistake eC.1 MISSING & IN scanf

Erroneous Code

int a;printf("Enter an integer:\t");scanf("%d", a); // missing & before a

Corrected Code:

int a;printf("Enter an integer:\t");scanf("%d", &a);

C Code Mistake eC.2 USING = INSTEAD OF == FOR COMPARISON

Erroneous Code

if (x = 1) // always evaluates as TRUEprintf("Found!\n");

Corrected Code

if (x == 1)printf("Found!\n");

C.11 Common Mistakes 541.e45

Page 46: Digital Design and Computer Architecture: ARM® Edition

C Code Mistake eC.3 INDEXING PAST LAST ELEMENT OF ARRAY

Erroneous Code

int array[10];array[10] = 42; // index is 0-9

Corrected Code

int array[10];array[9] = 42;

C Code Mistake eC.4 USING = IN #define STATEMENT

Erroneous Code

// replaces NUM with "= 4" in code#define NUM = 4

Corrected Code

#define NUM 4

C Code Mistake eC.5 USING AN UNINITIALIZED VARIABLE

Erroneous Code

int i;if (i == 10) // i is uninitialized

...

Corrected Code

int i = 10;if (i == 10)

...

C Code Mistake eC.6 NOT INCLUDING PATH OF USER-CREATED HEADERFILES

Erroneous Code

#include "myfile.h"

Corrected Code

#include "othercode\myfile.h"

Debugging skills are acquiredwith practice, but here are afew hints.

• Fix bugs starting with thefirst error indicated by thecompiler. Later errors maybe downstream effects ofthis error. After fixing thatbug, recompile and repeatuntil all bugs (at least thosecaught by the compiler!) arefixed.

• When the compiler says avalid line of code is in error,check the code above it (i.e.,for missing semicolons orbraces).

• When needed, split upcomplicated statements intomultiple lines.

• Use printf to outputintermediate results.

• When a result doesn't matchexpectations, startdebugging the code at thefirst place it deviates fromexpectations.

• Look at all compilerwarnings. While somewarnings can be ignored,others may alert you tomore subtle code errors thatwill compile but not run asintended.

C Code Mistake eC.7 USING LOGICAL OPERATORS (!, ||, &&) INSTEAD OFBITWISE (~, |, &)

Erroneous Code

char x=!5; // logical NOT: x = 0char y=5||2; // logical OR: y = 1char z=5&&2; // logical AND: z = 1

Corrected Code

char x=~5; // bitwise NOT: x = 0b11111010char y=5|2;// bitwise OR: y = 0b00000111char z=5&2;// logical AND: z = 0b00000000

541.e46 APPENDIX C

Page 47: Digital Design and Computer Architecture: ARM® Edition

C Code Mistake eC.8 FORGETTING break IN A switch/case STATEMENT

Erroneous Code

char x = 'd';...switch (x) {

case 'u': direction = 1;case 'd': direction = 2;case 'l': direction = 3;case 'r': direction = 4;default: direction = 0;

}// direction = 0

Corrected Code

char x = 'd';...switch (x) {

case 'u': direction = 1; break;case 'd': direction = 2; break;case 'l': direction = 3; break;case 'r': direction = 4; break;default: direction = 0;

}// direction = 2

C Code Mistake eC.9 MISSING CURLY BRACES {}

Erroneous Code

if (ptr == NULL) // missing curly bracesprintf("Unable to open file.\n");exit(1); // always executes

Corrected Code

if (ptr == NULL) {printf("Unable to open file.\n");exit(1);

}

C Code Mistake eC.10 USING A FUNCTION BEFORE IT IS DECLARED

Erroneous Code

int main(void){

test();}

void test(void){...}

Corrected Code

void test(void){...}

int main(void){

test();}

C Code Mistake eC.11 DECLARING A LOCAL AND GLOBAL VARIABLEWITH THE SAME NAME

Erroneous Code

int x = 5; // global declaration of xint test(void){

int x = 3; // local declaration of x...

}

Corrected Code

int x = 5; // global declaration of xint test(void){

int y = 3; // local variable is y...

}

C.11 Common Mistakes 541.e47

Page 48: Digital Design and Computer Architecture: ARM® Edition

C Code Mistake eC.12 TRYING TO INITIALIZE AN ARRAY WITH {} AFTERDECLARATION

Erroneous Code

int scores[3];scores = {93, 81, 97}; // won't compile

Corrected Code

int scores[3] = {93, 81, 97};

C Code Mistake eC.13 ASSIGNING ONE ARRAY TO ANOTHER USING =

Erroneous Code

int scores[3] = {88, 79, 93};int scores2[3];

scores2 = scores;

Corrected Code

int scores[3] = {88, 79, 93};int scores2[3];

for (i=0; i<3; i++)scores2[i] = scores[i];

C Code Mistake eC.14 FORGETTING THE SEMI-COLON AFTER A do/whileLOOP

Erroneous Code

int num;do {

num = getNum();} while (num < 100) // missing ;

Corrected Code

int num;do {

num = getNum();} while (num < 100);

C Code Mistake eC.15 USING COMMAS INSTEAD OF SEMICOLONS IN forLOOP

Erroneous Code

for (i=0, i < 200, i++)...

Corrected Code

for (i=0; i < 200; i++)...

C Code Mistake eC.16 INTEGER DIVISION INSTEAD OF FLOATING POINTDIVISION

Erroneous Code

// integer (truncated) division occurs when// both arguments of division are integersfloat x = 9 / 4; // x = 2.0

Corrected Code

// at least one of the arguments of// division must be a float to// perform floating point divisionfloat x = 9.0 / 4; // x = 2.25

541.e48 APPENDIX C

Page 49: Digital Design and Computer Architecture: ARM® Edition

This appendix has focused on using C on a system such as a personalcomputer. Chapter 9 (available as a web supplement) describes howC is used to program an ARM-based Raspberry Pi computer that canbe used in embedded systems. Microcontrollers are usually programmedin C because the language provides nearly as much low-level control ofthe hardware as assembly language, yet is much more succinct and fasterto write.

C Code Mistake eC.18 GREAT EXPECTATIONS (OR LACK THEREOF)

A common beginner error is to write an entire program (usually with little modularity) andexpect it to work perfectly the first time. For non-trivial programs, writing modularcode and testing the individual functions along the way are essential. Debugging becomesexponentially harder and more time-consuming with complexity.

Another common error is lacking expectations. When this happens, the programmercan only verify that the code produces a result, not that the result is correct. Testing aprogram with known inputs and expected results is critical in verifying functionality.

C Code Mistake eC.17 WRITING TO AN UNINITIALIZED POINTER

Erroneous Code

int *y = 77;

Corrected Code

int x, *y = &x;*y = 77;

C.11 Common Mistakes 541.e49