Chapter 0 – C Programming. The C Language  We are programming in C, a subset of C++  C++ was originally compiled into C  No classes, templates, namespaces,

  • Published on

  • View

  • Download


<p>CSCI 3431: Operating Systems</p> <p>CSCI 3431: Operating SystemsChapter 0 C ProgrammingThe C LanguageWe are programming in C, a subset of C++C++ was originally compiled into CNo classes, templates, namespaces, user-defined overloading, streamsHere is a good reference to the language and the basic C libraries:'s FoundationsC is really just a structured version of assembly languageVery minimal library support (see handout)Meant for systems programming originally created as a language to program UnixC was programmed in a week and the manual was written after they determined what the compiler did/acceptedFundamentally linked to the Unix OS and to system programmingCreated by Brian Kernighan and Dennis Ritchie at Bell LabsDeveloped before mice, GUI'sIs a foundational language that spawned C++, Java, C# and many other more recent languagesA reference manual (online or paper) is essential </p> <p>PhilosophiesC is made to let a programmer do pretty much anything which means that it's easy to really botch something upIt was designed to be as close to assembly language as was comfortable for a programmerThe language is simple which means that complexity is handled by the programmer and programsPuts the emphasis on the programmer to develop good style, structure, and practices</p> <p>C versus JavaMuch of the two languages is similar (e.g., operators, control structures)Differences mainly occur in the type systemC is much simpler, but in turn, leads to very complex programse.g., complexity is in the programs, not the language as is the case with JavaC's libraries are similarly simple and easy to learn, but most find them hard to use because of their flexibility and the very low level of detailJava protects the programmer while C exposes the programmer, but this is partly due to historical contextThe File ModelAll C I/O is done using files3 special files are provided: stdin, stdout, and stderr These files are automatically opened and closed for you by the compilerstdin = keyboard, stdout = monitor, but both can be redirected as neededstderr also goes to the monitor, but is often redirected to a file to be used as an error logI/O can be done directly using fread() and fwrite()More useful to do formatted I/O using fprintf() and fscanf()File I/OFiles are represented by a file pointer of type FILE *Files must be opened (fopen) Files are opened to support a specific mode of useFiles should be closed (fclose)Files are often buffered so flushing might be necessary to force output (fflush)Buffering is controlled by the programmer (setvbuf) for one of:_IONBFNo buffering (unbuffered)_IOLBFLine buffering_IOFBFFull bufferingThe buffer size is also controllable to achieve optimum performance (usually matched to a disk block)File Mode Values"r"read"w"write"a"append"r+"reading and writing"w+"create then reading and writing (discard previous contents)"a+"open or create and do writing at end</p> <p>FILE *fp = fopen ("errors.txt","a+");File OutputFormatted: fprintf, printf, sprintf, vprintf ...fputc: write a char to a FILE *fputs: write a char* to a FILE *char* = null terminated stringputc: macro version of fputc that may evaluate its argument more than once (avoid using it)puts: write a char* to stdoutputchar: write a char to stdoutEach function has its own subtletiesYou MUST learn how to use these functions!</p> <p>Example: Writing a string(not necessarily efficiently or clearly)#include #include #define LENGTH 80</p> <p>int main(void) { FILE *stream = stdout; int i, ch; char buffer[LENGTH + 1] = "Hello world"; </p> <p> for (i = 0; (i &lt; strlen(buffer)) &amp;&amp; ((ch = putc(buffer[i], stream)) != EOF); ++i); } /* end main() */ /******************** Expected output: *************************Hello world */Formatted Outputfprintf(file, format, values);</p> <p>Various versions of fprintf() exist:printf(...) is the same as fprintf(stdout,...)sprintf(): print to a string (or character buffer)v_printf(): variable number or args (in the format)Other variations exist (see reference material)</p> <p>Formatted Outputprintf(format, args ...);</p> <p>Format contains format specifiers, such as %d (integer), %s (string), %c (character)There must be an argument for every specifierFormat can contain output modifiers such as \n to insert a newline </p> <p>printf(%d is %s than %d\n, i[0], smaller, max);Format Specifiers%flags (0ptional): sign, zero padding, etc.minimum width (optional).precision (optional): maximum charslength modifier (optional): short, longargument type conversion: string, pointer, character, float, integer, etc.</p> <p>%-2.8s, %hd, %*s</p> <p>Conversions (used by specifiers)</p> <p>sstringdsigned integer ffloat (double)csingle characterppointern displays the number of characters printed so farAll these are preceded by a % as part of the format specifierALL 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.Examples of Outputprintf ("Hello World\n");</p> <p>char buf[256];sprintf(buf,"%8d\t%8d", a, b);</p> <p>fprintf(stderr, "%s: fatal: %s not found", argv[0], argv[1]);</p> <p>FILE *log = fopen("log.txt","w+");fprintf(log,"%s: %s\n", time, msg);</p> <p>Command Line Arguments#include intmain (int argc, char**argv) { int i; for (i = 0; i &lt; argc; i++) { printf("Argument %d: %s\n", i, argv[i]); } return (i);} /* end main () */</p> <p>%&gt;./a.out h o testArgument 0: a.exeArgument 1: -hArgument 2: -oArgument 3: testC InputFormatted input is done using various versions of fscanffscanf(stdin,...) same as scanf(...)scanf() is hard to use at first!Also have:fgetc(), getc(), getchar(), fgets(), gets(), and ungetc()Each function has its own little quirksYou must learn to use the printf() and scanf() families of functions!Learning to read the documentation while you practice using them is crucialC InputTo match fprintf() for output there is fscanf(file,fmt,args) for input. E.g.,fscanf(stdin, %s %d, name, &amp;grade);Format specifiers are pretty similar, but do have a few differencesArgs MUST be addresses (pointers)name is a char*grade is an int so we use its addressscanf() Conversions</p> <p>/* Example: Tami Meredith, 2011 */#include </p> <p>#define debug 0#define COUNT 10#define SUCCESS 0</p> <p>int main (int argc, char** argv) { int i, data[COUNT], max = 0;</p> <p> for (i = 0; i &lt; COUNT; i++) { scanf("%d", &amp;data[i]);#if debug printf("%d: Read %d\n", i, data[i]);#endif if (data[i] &gt; data[max]) { max = i; } } printf("Max = %d\n", data[max]); return(SUCCESS);} /* end main () */</p> <p>C Operators1.Parentheses( ) [ ]L to R1.Structure Access . -&gt;R to L2.Unary! ~ ++ -- + - * &amp; (type) sizeofL to R3.Mult., Div., Modulus* / %L to R4.Add, Subtract+ -L to R5.Shift&gt;L to R6.Comparison&lt; &gt;=L to R7.Equality== != L to R8.Bitwise And&amp;L to R9.Bitwise Exor^L to R10.Bitwise Or|L to R11.Logical And&amp;&amp;L to R12.Logical Or||L to R13: Conditional?=L to R14.Assignment= += -= *= /= %= &amp;= ~= |= =R to L15. Comma,L to RControl StructuresPretty much the same as Javaf(), returnif () ... , if () ... else ...switch () { case _: ... default: ... }for (;;) ..., while () ..., do { ... } while ();break, continuef(), returnlabel:, goto Example: Switchswitch (c) { default: printf("This is just a mess \n"); case '\n': case '\t': printf("c is whitespace\n"); break; case '_': printf("c is an underscore"); break; default : printf("c is unspecified\n");}</p> <p>You can have more than one default. Cases can come in any order. If no break exists, execution "falls through" into the next case.</p> <p>Quirks and Tricksfor(i = 1, j=2; x &lt; 10; a++, b++) { }for (;;) { /* infinite loop */ }#define loop for(;;)continue jumps to test of a loopbreak exits innermost loop or switch a = (x &lt; y) ? x : y;printf("sex: %smale\n", (sex='f') ? "fe" : "");while ((c = getchar()) != EOF) { }x++; ++x; x += 1; x = x + 1;But x[i++] is not the same as x[++i]x = x * 2; x *= 2; x (b))?(a):(b))</p> <p>Macro Quirks#undef will undefine a macroe.g.: #undef COUNTMacros can be redefined if desiredToken concatenation is allowed in macro bodiese.g., #define cat(x,y) x ## ycat(var,123) produces var123#arg as a use causes stringificatione.g., #define string(x) #xstring(hi\n) produces "hi\n"</p> <p>Preprocessor#define COUNT 10#define MAX(x,y) (((x)&gt;(y))?(x):(y))#undef COUNT#include #include "myjunk.h"#ifdef CONST ccode #endif -- also ifndef#if defined(CONST) ccode #endif #if (1) ccode #endif#elif, #elseMakefilesmakefiles automatically build your program in Unix environments</p> <p>lab1: lab1.cgcc o lab1 lab1.c</p> <p>Format of entries in makefilefile: dependenciescommand</p> <p>To use type: makeWill use the first entry as the target by default</p> <p>Good CodeSimple, clearReadable, understandableMaintainableEfficient, but only sacrifice readability and maintainability if the efficiency is criticalUniform with regard to coding standardComments are "value added"Neither under nor over commentedCoding Thoughts 1Write it once only; if you duplicate code then refactor! (#bugs = LOC)No magic numbers; use symbolic constantsCheck for errors!Clarity before efficiency unless neededTrust the compiler to optimise for youMake things explicit; casts not conversionsAim for type consistency as much as possibleUse coding standards consistentlyCoding Thoughts 2Know your hardware (e.g., sizeof(int))Use sizeof instead of explicit numeric valuesYou may need to fflush(stdout) to ensure you see all your debugging outputIf you modify any typedef, you must recompile the entire programDon't delete code! Hide it with:#if 0 ... code ... #endifKeep backups! Make checkpoints; consider using a repository (e.g., subversion)Comments cannot be nestedAbstract Data TypesSeparation of interface and implementationPredates OOP, ClassesRequires programmer compliance/honestyE.g., stack, binary tree, hash tableOnly have Arrays, SUEs to create composite data typesInterface: predefined functions, SUEs, and types in the "public" header fileImplementation: function definitions in the C filepossible second "private" header file with implementation-specific SUEs, types, and declarationsA Simple List/* Private type declaration */typedef struct listruct { void *data; struct listruct *next;} list;</p> <p>/* Public Interface */list *newList(void);void *car(list *l);list *cdr(list *l);list *cons(void *d, list *l);int length(list *l);int isEmpty(list *l);Hungarian Notation (Charles Simonyi)Two variations existSystems Hungarian:Prefix identifiers with their actual physical data typee.g., piSum = pointer to an integerApplication Hungarian:Prefix identifiers with some useful semantic informatione.g., dVertical = difference/delta, rwVal = rowCLI Development on UnixEditor: vi, vimCompiler, Linker, PP: gccText tools: AWK, perl, m4Building: make, cmake, imakeSearch: grep, egrep, fgrepComparision: diff, diff3Debugging: gdb, lintProfiling: gprofRepository: subversion, cvs, rcs, gitUnix tools: bash, sort, uniq, ...GCC Flags-OxUse optimisation level x= 0,1,2,3 (none to most)-ccompile, do not link-Epreprocess only-Sgenerate assembly language-o namerename the output to name-WallIssue all warnings-WextraIssue extra warnings over Wall-WpedanticIssue all ISO C warnings-WerrorTurn warnings into errors-gEnable debugging support-ggdbEnable gdb support</p> <p>There are several hundred command line flags, these are just a few of the common ones you will useDebugging + optimisation can yield very strange results, best to turn optimisation off when debugging/* * Tami Meredith: Pipe example */#include #include #include #include #include #include </p> <p>#define BUFSIZE 64#define READING 0#define WRITING 1</p> <p>/* A variation on perror() */void failure (msg) char *msg;{ fprintf(stderr, "%s: error %d\n", msg, errno); exit(EXIT_FAILURE);} /* end failure () */</p> <p>int main (int argc, char **argv) {</p> <p> 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"); } </p> <p> for (i = 0; i &lt; 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",&amp;pid); sum = sum + pid; } } printf("Average is %f\n", sum/10.0); exit(EXIT_SUCCESS);} /* end main () */int fubar (argc, argv) int argc; char **argv; { ... }</p> <p>int fubar (int argc, char **argv) { ... }</p> <p>int fubar (int argc, char **argv) { ... }</p> <p>int fubar ( int argc, char **argv) { ... }</p> <p>int fubar (int argc, char **argv) { ... }</p> <p>There is a space after the name in the definition and not in any use to help search for definitions. e.g.: fubar(2,{"a.exe"}); Variations in StyleConfused?C can be completely unreadable, perhaps more so than any other languageIt takes decades to fully grasp C which is rather amazing since it's one of the smallest, most concise languages there isFor some fun, see:</p>


View more >