Chapter 0 C Programming CSCI 3431 OPERATING SYSTEMS

  • Slides: 51
Download presentation
Chapter 0 – C Programming CSCI 3431: OPERATING SYSTEMS

Chapter 0 – C Programming CSCI 3431: OPERATING SYSTEMS

The C Language We are programming in C, a subset of C++ was originally

The C Language We are programming in C, a subset of C++ was originally compiled into C No classes, templates, namespaces, userdefined overloading, streams Here is a good reference to the language and the basic C libraries: http: //www. acm. uiuc. edu/webmonkeys/book/c_guide/

C's Foundations C is really just a structured version of assembly language Very minimal

C's Foundations C is really just a structured version of assembly language Very minimal library support Meant for systems programming – originally created as a language to program Unix Created by Brian Kernighan and Dennis Ritchie at Bell Labs Developed before mice, GUI's A reference manual (online or paper) is essential

The File Model All C I/o is done using files 3 special files are

The File Model All C I/o is done using files 3 special files are provided: stdin, stdout, and stderr These files are automatically opened and closed for you by the compiler I/0 can be done directly using fread() and fwrite() More useful to do formatted I/o using fprintf() and fscanf()

Formatted Output fprintf(file, “format”, values); Various version of fprintf() exist: printf(. . . )

Formatted Output fprintf(file, “format”, values); Various version of fprintf() exist: printf(. . . ) is the same as fprintf(stdout, . . . ) sprintf(): print to a string (or character buffer) v_printf(): variable number or args Other output functions are also available: fputc(), putchar(), puts() Each function has its own subtleties You MUST learn how to use these functions!

Formatted Output printf(“format”, args. . . ); 1. Format contains format specifiers, such as

Formatted Output printf(“format”, args. . . ); 1. Format contains format specifiers, such as %d (integer), %s (string), %c (character) 2. There must be an argument for every specifier 3. Format can contain output modifiers such as n to insert a newline printf(“%d is %s than %dn”, i[0], “smaller”, max);

Conversions s string d signed integer f float (double) c single character p pointer

Conversions s string d signed integer f float (double) c single character p pointer Many others exist for alternative numeric formats n displays the number of characters printed so far

ALL the Conversions. . . %c The character format specifier. %d The integer format

ALL the Conversions. . . %c The character format specifier. %d The integer format specifier. %i The integer format specifier (same as %d). %f The floating-point format specifier. %e The scientific notation format specifier. %E The scientific notation format specifier. %g Uses %f or %e, whichever result is shorter. %G Uses %f or %E, whichever result is shorter. %o The unsigned octal format specifier. %s The string format specifier. %u The unsigned integer format specifier. %x The unsigned hexadecimal format specifier. %X The unsigned hexadecimal format specifier. %p Displays the corresponding argument that is a pointer. %n Records the number of characters written so far. %% Outputs a percent sign.

Format Specifiers 1. 2. 3. 4. 5. 6. % flags (0 ptional): sign, zero

Format Specifiers 1. 2. 3. 4. 5. 6. % flags (0 ptional): sign, zero padding, etc. minimum width (optional). precision (optional): maximum chars length modifier (optional): short, long argument type conversion: string, pointer, character, float, integer, etc. %-2. 8 hs, %d, %*s

Examples of Output printf ("Hello Worldn"); char buf[256]; sprintf(buf, "%8 dt%8 d", a, b);

Examples of Output printf ("Hello Worldn"); char buf[256]; sprintf(buf, "%8 dt%8 d", a, b); fprintf(stderr, "%s: fatal: %s not found", argv[0], argv[1]); FILE *log = fopen("log. txt", "w+"); fprintf(log, "%s: %sn", time, msg);

File Mode Values "r" "w" "a" "r+" "w+" "a+" read write append reading and

File Mode Values "r" "w" "a" "r+" "w+" "a+" read write append reading and writing create then reading and writing and discard previous contents open or create and do writing at end

C Input To match fprintf() for output there is fscanf(file, fmt, args) for input.

C Input To match fprintf() for output there is fscanf(file, fmt, args) for input. E. g. , fscanf(stdin, “%s %d”, name, &grade); Format specifiers are pretty similar, but do have a few differences Args MUST be addresses (pointers) name is a char* grade is an int so we use its address

scanf() Conversions

scanf() Conversions

More on Input Various versions of fscanf() exist fscanf(stdin, . . . ) same

More on Input Various versions of fscanf() exist fscanf(stdin, . . . ) same as scanf(. . . ) scanf() is hard to use at first! Also have: fgetc(), getchar(), fgets(), and ungetc() Each function has its own little quirks You must learn to use the printf() and scanf() families of functions!

/* Lab 1 Solution, Tami Meredith, 2011 #include <stdio. h> */ #define debug 0

/* Lab 1 Solution, Tami Meredith, 2011 #include <stdio. h> */ #define debug 0 #define COUNT 10 #define SUCCESS 0 int main (int argc, char** argv) { int i, data[COUNT], max = 0; for (i = 0; i < COUNT; i++) { scanf("%d", &data[i]); #if debug printf("%d: Read %dn", i, data[i]); #endif if (data[i] > data[max]) { max = i; } } printf("Max = %dn", data[max]); return(SUCCESS); } /* end main () */

C Operators 1. Parentheses 1. Structure Access 2. Unary 3. Mult. , Div. ,

C Operators 1. Parentheses 1. Structure Access 2. Unary 3. Mult. , Div. , Modulus 4. Add, Subtract 5. Shift 6. Comparison 7. Equality 8. Bitwise And 9. Bitwise Exor 10. Bitwise Or 11. Logical And 12. Logical Or 13: Conditional 14. Assignment 15. Comma ()[]. -> ! ~ ++ -- + - * & (type) sizeof * /% +<< >> < <= > >= == != & ^ | && || ? = = += -= *= /= %= &= ~= |= <<= >>= , L to R R to L L to R L to R L to R R to L L to R

Control Structures if (). . . , if (). . . else. . .

Control Structures if (). . . , if (). . . else. . . switch () { case _: . . . default: . . . } for (; ; ). . . , while (). . . , do {. . . } while (); break, continue label: , goto f(), return

Type Definitions Type synonyms Just an alternative name for a type Often used to

Type Definitions Type synonyms Just an alternative name for a type Often used to improve code portability Type system uses structural equivalence, not name equivalence typedef int number; int x = 5; number y; y = x; /* Allowed, both are ints */

Def before Use All C variables must be defined (or declared) before they are

Def before Use All C variables must be defined (or declared) before they are used. Good style is to put all variable definitions at the beginning of a function. Was NOT originally block scoped and had only file and function scoping Many C programmers do not use block scoping as a result (I don't)

Pre. Defined Namespaces objects – "variables" functions typedef names enum constants labels SUE tags

Pre. Defined Namespaces objects – "variables" functions typedef names enum constants labels SUE tags Fields per SU

Structures A "class" with only data fields Structure (and union, enum) "tags" have their

Structures A "class" with only data fields Structure (and union, enum) "tags" have their own namespace tags are optional – usually leave them out in a typedef struct { int x, y; } t_point; t_point origin = { 0, 0 }; printf("x: %d, y: %dn", origin. x, origin. y);

Enumerations A way of giving names to an ordered set of integers typedef enum

Enumerations A way of giving names to an ordered set of integers typedef enum { club = 0, diamond, spade, heart } t_suit; typedef enum { ace = 1, two, . . . , jack, queen, king, } t_kind; typedef struct { t_kind k; t_suit s; } t_card; t_card = { king, club };

Pointers int x = 5; int *p; p = &x; printf ("%d %d", x,

Pointers int x = 5; int *p; p = &x; printf ("%d %d", x, *p); * : = "is a pointer" or "take value of" & : = "take address of"

Function Pointers void bsearch ( const void *key, const void *base, size_t n, size_t

Function Pointers void bsearch ( const void *key, const void *base, size_t n, size_t size, int (*cmp)(const void *keyval, const void *datum) ); char data[256][64]; bsearch("tami", data, 64*sizeof(char), 256, strcmp);

Complex Declarations char **argv pointer to char int (*daytab)[13] pointer to array[13] of int

Complex Declarations char **argv pointer to char int (*daytab)[13] pointer to array[13] of int *daytab[13] array[13] of pointer to int void *comp() function return pointer to void (*comp)() pointer to function returning void

Insane Declarations char (*(*x())[])() function returning pointer to array[] of pointers to functions returning

Insane Declarations char (*(*x())[])() function returning pointer to array[] of pointers to functions returning char(*(*x[3])())[5] array[3] of pointers to functions returning pointer to array[5] of chars

Type Specifiers New in ANSI C standard Two exist const may be initialised but

Type Specifiers New in ANSI C standard Two exist const may be initialised but not used in any subsequent assignment volatile lookup the value of the variable on every single access, do not cache, store in a register, or use in optimisation used for memory mapping implementation dependent; no required semantics

Storage Classes auto: give the variable automatic storage on the stack; can only be

Storage Classes auto: give the variable automatic storage on the stack; can only be used in functions register: try to keep the variable in a register; may by ignored; & cannot be used on register variables static inside functions, the variable retains it value between function calls (heap variable, not stack) outside functions, it indicates a variable declaration cannot be linked to other compilation units (files) extern : declare the variable; storage will be defined elsewhere and location determined at link time

Program Execution 1. Preprocessing: Remove #directives 2. Compilation a) b) c) d) e) Tokenisation:

Program Execution 1. Preprocessing: Remove #directives 2. Compilation a) b) c) d) e) Tokenisation: Stream of Tokens Parsing: Abstract Syntax Tree Semantic Analysis: Type checking etc. Optimisation: Register Transfer Language Code Generation and Optimisation 3. Linking: Produce a relocatable executable 4. Loading: Resolve virtual addresses 5. Execution

C Preprocessor Constructs Trigraph replacement: Obscure compliance with ISO 646 -1983 Invariant Code Set

C Preprocessor Constructs Trigraph replacement: Obscure compliance with ISO 646 -1983 Invariant Code Set Line Splicing: Lines that end with are joined File Inclusion: #include Macro Definition and Expansion: #define Conditional Compilation: #if Line Identification: Insertion of #line constructs Error Generation: #error causes CPP to write an error message Pragmas: Implementation dependent PP commands

Predefined CPP Names __LINE__ __FILE__ __DATE__ __TIME__ __STDC__ current source line current source file

Predefined CPP Names __LINE__ __FILE__ __DATE__ __TIME__ __STDC__ current source line current source file date of compilation time of compilation 1 if CC is standard-conforming Other names may be defined by the implementation

File Inclusion You are encouraged to create your own include files containing: Macros, Declarations,

File Inclusion You are encouraged to create your own include files containing: Macros, Declarations, Typedefs, Types, etc. Included files should not contain executable code! Two Variants 1. #include <file> Searches in the compilers include path for file 2. #include "file" Searches in a path from the CWD for file

Libraries 1 1. 2. 3. 4. 5. 6. 7. 8. assert. h: the assert()

Libraries 1 1. 2. 3. 4. 5. 6. 7. 8. assert. h: the assert() diagnostic macro ctype. h: character class tests errno. h: declaration of int errno; float. h: implementation limits for floats limits. h: implementation limits for integers locale. h: localization information math. h: mathematical functions setjmp. h: non-local jumps to avoid normal function calls and returns

Libraries 2 9. signal. h: signal handling and raising 10. stdarg. h: variable arg

Libraries 2 9. signal. h: signal handling and raising 10. stdarg. h: variable arg lists for functions 11. stddef. h: std. type defs (NULL, size_t, . . . ) 12. stdio. h: I/O, 1/3 of the C library 13. stdlib. h: utility (conversion, storage alloc. ) 14. string. h: string manipulation 15. time. h: time and date functions

Macros Not recursive, but args expanded/called multiple times Two variants: 1. #define identfier token-sequence

Macros Not recursive, but args expanded/called multiple times Two variants: 1. #define identfier token-sequence e. g. : #define loop while (1) #define COUNT 20 2. #define identifier(args) token-sequence e. g. : #define max((a), (b)) (((a)>(b))? (a): (b))

Macro Quirks #undef will undefine a macro e. g. : #undef COUNT Macros can

Macro Quirks #undef will undefine a macro e. g. : #undef COUNT Macros can be redefined if desired Token concatenation is allowed in macro bodies e. g. , #define cat(x, y) x ## y cat(var, 123) produces var 123 #arg as a use causes stringification e. g. , #define string(x) #x string(hin) produces "hin"

Preprocessor Summary #define #undef COUNT 10 MAX(x, y) (((x)>(y))? (x): (y)) COUNT #include <stdio.

Preprocessor Summary #define #undef COUNT 10 MAX(x, y) (((x)>(y))? (x): (y)) COUNT #include <stdio. h> #include "myjunk. h“ #ifdef CONST ccode #endif -- also ifndef #if defined(CONST) ccode #endif #if (1) ccode #endif #elif, #else

GCC Flags -Ox -c -E -S -o name -Wall -g -ggdb Use optimisation level

GCC Flags -Ox -c -E -S -o name -Wall -g -ggdb Use optimisation level x= 0, 1, 2, 3 (none to most) compile, do not link preprocess only generate assembly language rename the output to name Issue all warnings Enable debugging support Enable gdb support There are several hundred command line flags, these are just a few of the common ones you will use Debugging + optimisation can yield very strange results, best to turn optimisation off when debugging

Makefiles makefiles automatically build your program in Unix environments lab 1: lab 1. c

Makefiles makefiles automatically build your program in Unix environments lab 1: lab 1. c gcc –o lab 1. c Format of entries in makefile: dependencies <tab>command To use type: make Will use the first entry as the target by default

# Sample Makefile # By: Tami Meredith all: foobar. exe clean: rm –f foobar.

# Sample Makefile # By: Tami Meredith all: foobar. exe clean: rm –f foobar. exe *. o OBJS = foo. o bar. o FLAGS = -Wall –O 3 foobar. exe: $(OBJS) gcc -o foobar. exe $(FLAGS) $(OBJS) foo. o: foo. c gcc –c –o foo. o $(FLAGS) foo. c bar. o: bar. c gcc –c –o bar. o $(FLAGS) bar. c fb. h: touch *. c

Good Code Simple, clear Readable, understandable Maintainable Efficient, but only sacrifice readability and maintainability

Good Code Simple, clear Readable, understandable Maintainable Efficient, but only sacrifice readability and maintainability if the efficiency is critical Uniform with regard to coding standard Comments are "value added" Neither under nor over commented

Coding Thoughts 1 Write it once only; if you duplicate code then refactor! (#bugs

Coding Thoughts 1 Write it once only; if you duplicate code then refactor! (#bugs = LOC) No magic numbers; use symbolic constants Check for errors! Clarity before efficiency unless needed Trust the compiler to optimise for you Make things explicit; casts not conversions Aim for type consistency as much as possible Use coding standards consistently

Coding Thoughts 2 Know your hardware (e. g. , sizeof(int)) Use sizeof instead of

Coding Thoughts 2 Know your hardware (e. g. , sizeof(int)) Use sizeof instead of explicit numeric values You may need to fflush(stdout) to ensure you see all your debugging output If you modify any typedef, you must recompile the entire program Don't delete code! Hide it with: #if 0. . . code. . . #endif Keep backups! Make checkpoints; consider using a repository (e. g. , subversion) Comments cannot be nested

Abstract Data Types Separation of interface and implementation Predates OOP, Classes Requires programmer compliance/honesty

Abstract Data Types Separation of interface and implementation Predates OOP, Classes Requires programmer compliance/honesty E. g. , stack, binary tree, hash table Only have Arrays, SUEs to create composite data types Interface: predefined functions, SUEs, and types in the "public" header file Implementation: function definitions in the C file possible second "private" header file with implementation- specific SUEs, types, and declarations

A Simple List /* Private type declaration */ typedef struct listruct { void *data;

A Simple List /* Private type declaration */ typedef struct listruct { void *data; struct listruct *next; } list; /* Public Interface */ list *new. List(void); void *car(list *l); list *cdr(list *l); list *cons(void *d, list *l); int length(list *l); int is. Empty(list *l);

Hungarian Notation (Charles Simonyi) Two variations exist Systems Hungarian: Prefix identifiers with their actual

Hungarian Notation (Charles Simonyi) Two variations exist Systems Hungarian: Prefix identifiers with their actual physical data type e. g. , pi. Sum = pointer to an integer Application Hungarian: Prefix identifiers with some useful semantic information e. g. , d. Vertical = difference/delta, rw. Val = row

CLI Development on CS Editor: vi, vim Compiler, Linker, PP: gcc Text tools: AWK,

CLI Development on CS Editor: vi, vim Compiler, Linker, PP: gcc Text tools: AWK, perl, m 4 Building: make, cmake, imake Search: grep, egrep, fgrep Comparision: diff, diff 3 Debugging: gdb, lint Profiling: gprof Repository: subversion, cvs, rcs Unix tools: bash, sort, uniq, . . .

/* * Tami Meredith: Class Example: Pipes */ #include <sys/types. h> #include <errno. h>

/* * Tami Meredith: Class Example: Pipes */ #include <sys/types. h> #include <errno. h> #include <unistd. h> #include <stdio. h> #include <string. h> #include <stdlib. h> #define BUFSIZE #define READING #define WRITING 64 0 1 /* A variation on perror() */ void failure (msg) char *msg; { fprintf(stderr, "%s: error %dn", msg, errno); exit(EXIT_FAILURE); } /* end failure () */

int main (argc, argv) int argc; char **argv; { int main (int argc, char

int main (argc, argv) int argc; char **argv; { int main (int argc, char **argv) { int main ( int argc, char **argv ) { int main (int argc, char **argv) { /* space after name in dec/def, not in use to help search e. g. : main(2, {"a. exe"}); */

int main (int argc, char **argv) { pid_t pid; int p[2], i, sum =

int main (int argc, char **argv) { pid_t pid; int p[2], i, sum = 0; char buf[BUFSIZE]; /* Create pipe BEFORE we fork (so both have it) */ if (pipe(p) == -1) { failure ("pipe allocation failure"); } for (i = 0; i < 10; i++) { if ((pid = fork()) == -1) { failure ("can't fork"); } if (pid == 0) { /* Child process writes */ sprintf(buf, "%d", getpid()); write(p[WRITING], buf, strlen(buf)+1); exit(EXIT_SUCCESS); } else { /* Parent reads */ read(p[READING], buf, BUFSIZE); sscanf(buf, "%d", &pid); sum = sum + pid; } } printf("Average is %fn", sum/10. 0); exit(EXIT_SUCCESS); } /* end main () */