CS代考 CITS2002 Systems Programming

CITS2002 Systems Programming
1 next ¡ú CITS2002 CITS2002 schedule
The structure of C programs
Let’s looks at the high-level structure of a short C program, rotate.c (using ellipsis to omit some statements for now).
At this stage it’s not important what the program is supposed to do.
Of note in this example:
Characters such as a space, tab, or newline, may appear almost anywhere – they are stripped out and ignored by the C compiler.
We use such
whitespace
characters to provide a layout to our programs. While the exact layout is not important, using a consistent layout is very good practice.
Keywords, in bold, mean very specific things to the C compiler.
Lines commencing with a ‘#’ in blue are processed by a separate program, named the C preprocessor.
In practice, our program is provided as input to the preprocessor,
#include #include #include #include
/* Compile this program with:
cc -std=c99 -Wall -Werror -pedantic -o rotate rotate.c
#define ROT 13
static char rotate(char c) {
c = c + ROT; …..
int main(int argcount, char *argvalue[]) {
// check the number of arguments
if(argcount != 2) { ….
exit(EXIT_FAILURE); }
else { ….
exit(EXIT_SUCCESS); }
return 0; }
preprocessor, and the preprocessor’s output is given to the C compiler.
Lines in green are comments. They are ignored by the C compiler, and may contain (almost) any characters.
C99 provides two types of comments –
/* block comments */ and
// comments to the end of a line
CITS2002 Systems Programming, Lecture 2, p1, 27th July 2021.
CITS2002 Systems Programming
¡ûprev 2 next¡ú CITS2002 CITS2002schedule
The structure of C programs, continued
#include #include #include #include
/* Compile this program with:
cc -std=c99 -Wall -Werror -pedantic -o rotate rotate.c
#define ROT 13
static char rotate(char c)
c = c + ROT;
return c; }
int main(int argcount, char *argvalue[]) {
// check the number of arguments
if(argcount != 2) { ….
exit(EXIT_FAILURE); }
else { ….
exit(EXIT_SUCCESS); }
return 0; }
Same program, but more to note:
A variety of brackets are employed, in pairs, to group together items to be considered in the same way. Here:
angle brackets enclose a filename in a #include directive,
round brackets group items in arithmetic expressions and function calls,
square brackets enclose the index when access arrays (vectors and matrices…) of data, and
curly brackets group together sequences of one or more statements in C. We term a group of statements a block of
a block of statements.
Functions in C, may be thought of as a block of statements to which we give a name. In our example, we have two functions – rotate() and main().
When our programs are run by the operating system, the operating system always starts our program from main(). Thus, every complete C program requires a main() function.
The operating system passes some special information to our main() function, command-line arguments, and main() needs a special syntax to receive these.
Most C programs you read will name main()’s parameters as argc and argv.
When our program finishes its execution, it returns some information to the operating system. Our example here exits by announcing either its failure or success.
CITS2002 Systems Programming, Lecture 2, p2, 27th July 2021.
CITS2002 Systems Programming
¡ûprev 3 next¡ú CITS2002 CITS2002schedule
Compiling and linking our C programs
C programs are human-readable text files, that we term source-code files.
This makes them very easy to copy, read, and edit on different computers and different operating systems.
C is often described as being portable at the source-code level.
Before we can run (execute) our C programs, we must translate, or compile, their source-code files to files that the operating system can better manage.
A program known as a compiler translates (compiles) source-code files intoobject-code files.
Finally, we translate or link one or more object-code files to produce anexecutable program, often termed a ‘binary’, an ‘executable’, or an ‘exe’ file.
A program known as a linker performs this translation, also linking our object-code file(s) withstandard libraries and (optionally) 3rd-party libraries.
Depending on how we invoke the compiler, sometimes we can ‘move’ straight from the source-code files to the executable program, all in one step.
In reality the compiler is ‘silently’ executing the linker program for us, and then removing any unwanted object-files.
CITS2002 Systems Programming, Lecture 2, p3, 27th July 2021.
CITS2002 Systems Programming
¡ûprev 4 next¡ú CITS2002 CITS2002schedule
Variables are locations in a computer’s memory. A typical desktop or laptop computer will have 4-16GB of memory, or four-sixteen billion addressable memory locations,
A typical C program will use 4 bytes to hold a single integer value, or 8 bytes to hold a single floating-point value.
Any variable can only hold a single value at any time – they do not maintain a history of past values they once had.
Naming our variables
To make programs more readable, we provide variables with simple names. We should carefully choose names to reflect the role of the variable in our programs.
While variable names can be almost anything (but not the same as the keywords in C) there’s a simple restriction on the permitted characters in a name –
they must commence with an alphabetic or the underscore character (_ A-Z a- z), and
be followed by zero or more alphabetic, underscore or digit characters (_ A-Z a- z 0-9).
C variable names are case sensitive, thus:
MYLIMIT, mylimit, Mylimit and MyLimit
are four different variable names.
While not required, it’s preferred that variable names do not consist entirely of uppercase characters.
We’ll consistently use uppercase-only names for constants provided by the C preprocessor, or user-defined type names:
MAXLENGTH, AVATAR, BUFSIZ, and ROT
Older C compilers limited variable names to, say, 8 unique characters. Thus, for them, turn_nuclear_reactor_coolant_on and turn_nuclear_reactor_coolant_off
are the same variable! Keep this in mind if ever developing portable code for old environments.
CITS2002 Systems Programming, Lecture 2, p4, 27th July 2021.
CITS2002 Systems Programming
¡ûprev 5 next¡ú CITS2002 CITS2002schedule
Basic datatypes
Variables are declared to be of a certain datatype, or just type.
We use different types to represent the permissible values that a program’s variable has.
For example, if we’re using a variable to just count things, we’ll use an integer variable to hold the count; if performing trigonometry on angles expressed in radians, we’ll use floating-point variables to hold values with both an integral and a fractional part.
C provides a number of standard, or base types to hold commonly required values, and later we’ll see how we can also define our own user-defined types to meet our needs.
Let’s look quickly at some of C’s base datatypes:
description, and an example of variable initialization
Boolean (truth values), which may only hold the values of either true or false e.g. boolfinished=false;
integer values, negative, positive, and zero e.g. int year = 2006;
character values, to each hold a single values such as an alphabetic character, a digit character, a space, a tab…
e.g. char initial = ‘C’;
floating point values, with a typical precision of 10 decimal digits (on our lab machines)
e.g. float inflation = 4.1;
“bigger” floating point values, with a typical precision of 17 decimal digits (on our lab machines)
e.g. double pi = 3.1415926535897932;
Some textbooks will (too quickly) focus on the actual storage size of these basic types, and emphasise the ranges of permissible values. When writing truly portable programs – that can execute consistently across different hardware architectures and operating systems – it’s important to be aware of, and avoid, their differences. We’ll examine this issue later, but for now we’ll focus on using these basic types in their most obvious ways.
From where does the bool datatype get its name? – the 19th century mathematician and philosopher, .
CITS2002 Systems Programming, Lecture 2, p5, 27th July 2021.
CITS2002 Systems Programming
¡ûprev 6 next¡ú CITS2002 CITS2002schedule
The Significance of Integers in C
Throughout the 1950s, 60s, and 70s, there were many more computer hardware manufacturers than there are today. Each company needed to promote its own products by distinguishing them from their competitors.
At a low level, different manufacturers employed different memory sizes for a basic character – some just 6 bits, some 8 bits, 9, and 10. The unfortunate outcome was the incompatability of computer programs and data storage formats.
The C programming language, developed in the early 1970s, addressed this issue by not defining the required size of its datatypes. Thus, C programs are portable at the level of their source code – porting a program to a different computer architecture is possible, provided that the programs are compiled on (or for) each architecture. The only requirement was that:
sizeof(char) ¡Ü sizeof(short) ¡Ü sizeof(int) ¡Ü sizeof(long)
Since the 1980s, fortunately, the industry has agreed on 8-bit characters or bytes. But (compiling and) running the C program on different architectures:
may produce different (though still correct) results:
It’s permissible for different C compilers on different architectures to employ different sized integers.
Why does this matter? Different sized integers can store different maximum values – the above datatypes are signed (supporting positive and negative values) so a 4-byte integer can only represent the values -2,147,483,648 to 2,147,483,647.
If employing integers for ‘simple’ counting, or looping over a known range of values, there’s rarely a problem. But if using integers to count many (small) values, such as milli- or micro- seconds, it matters:
Fun fact: GPS uses 10 bits to store the week. That means it runs out… oh heck ? April 6, 2019
Airlines Have To Reboot Their Airbus A350 Planes After Every 149 Hours To keep a Boeing Dreamliner flying, reboot once every 248 days
#include
int main(void) {
printf(“char %lu\n”, sizeof(char)); printf(“short %lu\n”, sizeof(short)); printf(“int %lu\n”, sizeof(int)); printf(“long %lu\n”, sizeof(long)); return 0;
CITS2002 Systems Programming, Lecture 2, p6, 27th July 2021.
CITS2002 Systems Programming
¡ûprev 7 next¡ú CITS2002 CITS2002schedule
The scope of variables
The scope of a variable describes the range of lines in which the variable may be used. Some textbooks may also term this the visibility or lexical range of a variable.
C has only 2 primary types of scope:
global scope (sometimes termed file scope) in which variables are declared outside of all functions and statement blocks, and
block scope in which variables are declared within a function or statement block. The variable count has
global scope.
It is defined on line 06, and may be used anywhere from line 06 until the end of the file (line 26).
The variable count is also preceded by the keyword static, which prevents it from being ‘seen’ (read or written) from outside of this file rotate.c
The variable nfound has block scope.
It is defined on line 10, and may be used anywhere from line 10 until the end of the block in which it was defined (until line 26).
The variable nerrors has block scope.
It is defined on line 14, and may be used anywhere from line 14 until line 18.
The variable ntimes has block scope.
It is defined on line 20, and may be used anywhere from line 20 until line 24.
01 #include 02 #include 03 #include 04 #include 05
06 static int count = 0;
08 int main(int argcount, char *argvalue[]) 09 {
int nfound = 0;
// check the number of arguments
if(argcount != 2) { int nerrors = 1;
exit(EXIT_FAILURE); }
int ntimes = 100;
exit(EXIT_SUCCESS); }
We could define a different variable named nerrors in the block of lines 20-24 – without problems.
We could define a different variable named nfound in the block of lines 20-24 – but this would be a very bad practice!
CITS2002 Systems Programming, Lecture 2, p7, 27th July 2021.
CITS2002 Systems Programming
¡ûprev 8 next¡ú CITS2002 CITS2002schedule
Flow of control in a C program
A program’s control flow describes how sequences of statements are executed.
Flow control in a C program is very similar to most other imperative and object-oriented languages.
C programs commence their execution at their main() function, execute their statements, and exit (return the flow of control) to the operating system.
It’s fairly obvious that statements need to be executed in a well-defined order, as we expect programs to always behave the same way (unless some random data directs the execution path, as in computer games, simulations, and heuristic algorithms).
Default flow of control executes each statement in order, top-to-bottom.
Programs that only execute from top-to-bottom are pretty boring, and we need to control
their flow with a variety of conditional statements, loops, and function-calls.
CITS2002 Systems Programming, Lecture 2, p8, 27th July 2021.
CITS2002 Systems Programming
¡ûprev 9 next¡ú CITS2002 CITS2002schedule
Conditional execution
Conditional statements first evaluate a Boolean condition and then, based on whether it’s true or false, execute other statements.
The most common form is: Sometimes, the else clause is omitted: Often, the else clause provides further if statements:
if(condition) {
// more statements;
// more statements;
if(condition) {
// more statements;
if(condition1) {
// more statements;
else if(condition2) {
// more statements;
// more statements;
Note that in the examples, above, each block of statements to be executed has been written within curly-brackets.
The curly-brackets are not required (we could just write a single statement for eitherif or else clause). However, adding curly-
brackets is considered a good practice. They provide a safeguard for when additional statements are added later.
CITS2002 Systems Programming, Lecture 2, p9, 27th July 2021.
CITS2002 Systems Programming
¡ûprev 10 next¡ú CITS2002 CITS2002schedule
Boolean values
Of significance, and a very common cause of errors in C programs, is that C standards, prior to ISO-C99, had no Boolean datatype. Historically, an integer value of zero evaluated equivalent to a Boolean value of false; any non-zero integer value evaluated astrue.
You may read some older C code: which may be badly and accidently coded as: so, employ defensive programming:
In the second example, the conditional test always evaluates to false, as the single equals character requests an assignment, not a comparison. It is possible (and occassionally reasonable) to perform an assignment as part of a Boolean condition –
you’ll often see:
while( (nextch = getc(file) ) != EOF ) {….
Whenever requiring the true and false constants (introduced in C99), we need to provide the line: #include
CITS2002 Systems Programming, Lecture 2, p10, 27th July 2021.
int initialised = 0; // set to false ….
if(! initialised) {
// initialisation statements;
initialised = 1; // set to true }
int initialised = 0; // set to false ….
if(initialised = 0) {
// initialisation statements;
initialised = 1; // set to true }
int initialised = 0; // set to false ….
if(0 = initialised) // invalid syntax! {
// initialisation statements;
initialised = 1; // set to true }
CITS2002 Systems Programming
¡ûprev 11 next¡ú CITS2002 CITS2002schedule
Switch statements
When the same (integer) expression is compared against a number of distinct values, it’s preferred to evaluate the expression once, and compare it with possible values:
Cascading if..else..if.. statements: The equivalent switch Less-common features of the switch statement: statement:
if(expression == value1)
else if(expression == value2) {
// more statements;
// more statements;
// more statements;
switch(expression)
case value1 :
// more statements;
case value2 :
default : {
// more statements;
// more statements;
switch(expression)
case value1 : case value2 : {
// handle either value1 or value2 …..
case value3 : {
// more statements;
// no ‘break’ statement, drop through
default : {
// more statements;
Typically the ‘expression’ is simply an identifier, but it may be arbitrarily complex – such as an arithmetic expression, or a function call.
The datatype of the ‘expression’ must be an integer (which includes characters, Booleans, and enumerated types), but it cannot be a real or floating-point datatype.
The break statement at the end of eachcase indicates that we have finished with the ‘current’ value, and control-flow leaves the switch statement.
Without a break statement, control-flow continues “downwards”, flowing into the next case branch (even though the expression does not have that case’s value!).
switch statements with ‘dense’ values (none, or few integer missing) provide good opportunities for optimised code.
CITS2002 Systems Programming, Lecture 2, p11, 27th July 2021.
CITS2002 Systems Programming
¡ûprev 12 next¡ú CITS2002 CITS2002schedule
Flow of control in a C program – bounded loops
One of the most powerful features of computers, in general, is to perform thousands, millions, of repetitive tasks quickly
(in fact, one of the motivating first uses of computers in the 1940s was to calculate trigonometric tables for the firing of artillery shells).
C provides its for control statement toloop through a sequence of statements, ablock of statements, a known number of times:
The most common form appears below, in which we introduce The loop control variable does not always have to be an a loop control variable, i, to count how many times we go integer:
through the loop:
// here, variable i holds the values 1,2,…10
for(int i = 1 ; i <= 10 ; i = i+1) // the above introduced a loop-control variable, i printf("loop number %i\n", i); ..... // variable i is available down to here // but variable i is not available from here // here, variable ch holds each lowercase value for(char ch = 'a' ; ch <= 'z' ; ch = ch+1) { printf("loop using character '%c'\n", ch); ..... Notice that in both cases, above, we have introduced new variables, here i and ch, to specifically control the loop. The variables may be used inside each loop, in the statement block, but then "disappear" once the block is finished (after its bottom curly bracket). It's also possible to use any other variable as the loop control variable, even if defined outside of the for loop. In general, we'll try to avoid this practice - unless the value of the variable isrequired outside of the loop. CITS2002 Systems Programming, Lecture 2, p12, 27th July 2021. CITS2002 Systems Programming ¡ûprev 13 next¡ú CITS2002 CITS2002schedule Flow of control in a C program - unbounded loops The for loops that we've just seen should be used when we know, ahead of time, how many times we need to loop (i.e. 10 times, or over the range 'a'..'z'). Such loops are termed bounded loops and, unless we've made an unseen coding error, always terminate after a fixed number of iterations.