Week2 Combine
Week2 Combine
       What is C?
       C’s Strengths
       Why not C?
       History of C
       Procedural Paradigm
       Organization of C Programs
       Writing and Calling Functions
       Creating and Running a C Program
       C Programs with Multiple Source Files
       Header Files: Interface vs. Implementation
    What is C? (1/3)
3
       C is a high-level language
         Providesconstructs for structured programming
         Supports functions and procedural paradigm
         Supports user-definable derived data types
     Simple
     Efficient
 Portable
 Standard library
 Powerful
     Flexible
    Why Not C?
7
      Lisp                               Algol
                                          68
              Algol
               60
    Fortran                         Pascal
BCPL
    COBOL                                    B
       History of C (2/2)
9
Simula
                              C89
                                       C99       C11        C18
                                                         f7
                  f4         f5           f6
     Organization of C Programs (2/3)
18
                                                      function C
            call function A
                                function B
           call function B
call function C
 Source                           Object
           Preprocess   Compile   File 1
 File 1
 Source                           Object
           Preprocess   Compile   File 2
 File 2
                                                            Executable
                                           Library   Link      File
                                           Object
                                            File 1
 Source                           Object
           Preprocess   Compile   File n
  File n
                                           Library
                                           Object
      one of these source files must        File m
             int main(void)
             {
               printf("Hello World\n");
               return 0;
             }
       Multiple Source Files (2/6):
34
       hello-decl.h
       // this is file hello-decl.h
       #include <stdio.h>
      2
                   1) File hello-decl.h is included to provide function
                   prototype (or declaration) of standard C library
                   function printf and function hello
     Compile       2) Pair of double quote delimiters " tells preprocessor
     only!!!   3   to search for header file in current directory
gcc –std=c11 –pedantic-errors –Wstrict-prototypes
-Wall –Wextra –Werror –c hello-defn.c –o hello-defn.o
         Multiple Source Files (4/6):
36
         driver.c
#include "hello-decl.h"
                                     File hello-decl.h is included
int main(void) {               1     to provide function prototype (or
  hello();                           declaration) of function hello
  return 0;
                         2
}
                          1
     #include <math.h>          File math.h is included to provide function
     #include <stdio.h>
                                prototype (or declaration) of standard C
     int main(void) {           library function sqrt
       double px = 0.0, py = 0.0;
       double qx = 3.0, qy = 4.0;
       double w = qx - px, h = qy - py;
                                                     Call to printf displays
       double dist = sqrt(w*w + h*h);
                                                     following line:
       printf("Distance is %f\n", dist);
       return 0;                                      Distance is 5.000000
     }                                  2
                 3
                              Shorthand for link object files with library file libm.a
In the process of building the GNU system, a number of free and open-source programming tools
were incubated including the GNU C compiler (GCC). Later a C++ compiler was developed and
translators and compilers for languages such as Ada, Fortran, Objective-C, and Objective-C++, and
Go were added. The addition of languages beyond C led to GCC having the meaning The GNU
Compiler Collection.
When building ready-to-run applications from C source code, a compiler is not sufficient; run-time
libraries, an assembler, and a linker, are also needed. The whole set of these tools is called a
compiler tool chain or compiler driver. This document describes the process of writing, compiling,
linking, and running C programs using the GCC C compiler driver.
series where is a positive natural number. For example, if the program is given value as
                                                     1 / 17
                              Introduction to Compilation Process [Prasanna Ghali]
The next phase called the implementation phase will use a specific programming language to
convert algorithm         into a computer program. This phase comprises of three steps: Code,
Test, and Debug. This document is concerned with filling in the details required by a C
programmer to implement the Code step. Once the executable program is created, the
programmer can continue with the Test and Debug steps of the implementation phase - these
steps are not discussed here.
Word processors such as Microsoft Word are not useful and functional for editing source files
because they save files in proprietary native formats incompatible with programming tools. Since
writing and editing code is a fundamental job of programmers, specialized text editors called
source code editors have been invented to make programmers become more productive and
efficient. The list of source code editors is lengthy ranging from the simple, no-frills text editors
such as vi on Linux and Notepad on Windows to complex integrated development environments
such as Visual Studio on Windows. We recommend Visual Studio Code since it is free, modern,
multi-platform [can be installed on macOS, Windows 10, Linux], supports almost every
programming language currently in use, and provides many functionalities useful to
programmers. Visual Studio Code is installed in all DigiPen labs. Begin here to get an overview of
the editor.
Begin by creating a folder in Windows called test . Type wsl on the command line to switch
from Windows to Linux. Using Visual Studio Code, create a file called sum.c in folder test . This
is easily done by typing the following in the bash shell [note that the $ represents the Linux shell
prompt and is not a part of the command]:
                                                     2 / 17
                              Introduction to Compilation Process [Prasanna Ghali]
1 $ code sum.c
      1   #include <stdio.h>
      2
      3   int main(void) {
      4       int n;
      5       printf("Enter a positive natural number: ");
      6       scanf("%d", &n);
      7
      8       int sum = 0;
      9       for (int i = 1; i <= n; ++i) {
  10              sum += i;
  11          }
  12          printf("Sum of first %d natural numbers is: %d\n", n, i);
  13          return 0;
  14      }
  15
To compile the file sum.c with GNU C compiler, use the following command:
This command will compile source code in sum.c to machine code and store it in an executable
file sum.out . The output file for the machine code is specified using -o option. If the -o option is
omitted, output is written to a default file called a.out .
  1       $ ./sum.out
  2       Enter a positive natural number: 100
  3       Sum of first 100 natural numbers is: 5050
The loader program in Linux will load executable file sum.out from disk to memory and cause
the CPU to begin executing the first instruction in function main .
                                                     3 / 17
                                 Introduction to Compilation Process [Prasanna Ghali]
Why does Linux require pathname ./sum.out and not the simpler and straightforward sum.out ?
When the name of an executable such as code or gcc is typed in the shell, the operating system
will search in directories specified in a variable called PATH . In fact, these directories can be
displayed by typing the command echo $PATH . If the plain sum.out is typed, command not
found is displayed by the shell since directory test [in which executable sum.out was created]
is not specified in variable PATH . In every shell, character . on the command line means current
directory. So, by typing ./sum.out , you're telling Linux "don't worry about directories in variable
PATH , just run executable sum.out in the current directory . ".
      1   #include <stdio.h>
      2
      3   int main(void) {
      4       int n;
      5       printf("Enter a positive natural number: ");
      6       scanf("%d", &n);
      7
      8       int sum = 0;
      9       for (int i = 1; i <= n; ++i) {
  10              sum += i
  11          }
  12          printf("Sum of first %d natural numbers is: %d\n", n, i);
  13          return 0;
  14      }
  15
Compiling sum.c with no options other than enforcing C11 [for brevity], the compiler prints the
following error message:
In addition to flagging incorrect syntax as errors, compilers provide many diagnostic warning
messages about potential coding errors. To demonstrate this, a subtle error is introduced in line
  : in function printf , the correct integer format specifier %d is replaced with incorrect floating-
point format specifier %f :
      1   #include <stdio.h>
      2
      3   int main(void) {
      4       int n;
                                                        4 / 17
                                Introduction to Compilation Process [Prasanna Ghali]
Compiling the now buggy source file sum.c with no options other than enforcing C11, the
following diagnostic warning is produced by the compiler:
Notice that the compiler does create executable sum.out . To prevent programmers from passing
off buggy software, gcc provides the -Werror option that prevents gcc from successful
compilation when diagnostic warnings are generated:
In other words, -Werror option converts diagnostic warnings to full blown errors and prevents
programmers from proceeding any further until these warnings are heeded by repairing source
code. Options -Wall and -Wextra turn on warning messages for many other common coding
errors listed here. What do these compilation options such as -std-c11 , -pedantic-errors , and
-Wstrict-prototypes mean? These options support the creation of compliant code and a
detailed explanation of these compilation options is provided in this section. Finding bugs is hard
and programmers appreciate when compilers provide varied options that flag potential bugs by
generating warnings. Therefore, it is important for students to use these options, as in:
                                                       5 / 17
                             Introduction to Compilation Process [Prasanna Ghali]
before submitting any code that will be used in assessments for this course. Non-compliance
could result in submitted code receiving zero points and/or failing grade.
As an example, the individual compilation stages will be examined using source file hello.c :
  1   #include <stdio.h>
  2
  3   int main(void) {
  4       int year = 2020;
  5       printf("Hello World %d!!!\n", year);
  6       return 0;
  7   }
  8
Although the code in source file hello.c is simple, it uses external header files [on line ] and
calls a C standard library function (on line ), and therefore exercises the entire compiler
toolchain.
The Preprocessor
The first stage of the compilation toolchain process is the use of the preprocessor. Think of the
preprocessor as a text editor that modifies a C source file according to preprocessing directives.
Before interpreting directives, the preprocessor performs a more basic global transformation on
the source file: all single-line and multi-line comments are replaced with single spaces.
                                                    6 / 17
                               Introduction to Compilation Process [Prasanna Ghali]
Preprocessing directives are lines in a source file that begin with character # . The # is followed
by an identifier that is the directive name. The include directive name involves inclusion of
header files. The define directive name involves macro expansion where a macro is a fragment
of C code which has been given a name. Directive names if , else , and elif allow conditional
compilation of the source file by allowing certain parts of the source file to be included or
excluded from the compilation process. This document is only concerned with include directive
name.
A header file is a file containing C declarations and macro definitions to be shared between
multiple source files. A programmer requests the use of a header file in a source file with
preprocessing directive #include . Line         of source file hello.c looks like this: #include
<stdio.h> . The author is asking the preprocessor to search for C standard library header file
stdio.h in the disk and then to replace line          with the contents of header file stdio.h . The
delimiters < and > indicate to the preprocessor that it must search the standard list of system
directories special to the compiler toolchain being used.
This stage of the compiler toolchain can be manually invoked like this:
In gcc , the output file is specified with the -o option. The resulting file hello.i is a
transformation of source file hello.c with comments replaced by a single space and line            of
source file hello.c replaced with contents of system header file stdio.h followed by the
remaining lines of the source file. This is confirmed by examining the contents of hello.i :
Notice that the purpose of including header file stdio.h is served because hello.i now
contains a function prototype of printf on line            so that the compiler proper can understand
the call to function printf on line . This is so that the cardinal rule in C and C++ that all names
must be declared before their first use is satisfied.
                                                      7 / 17
                                Introduction to Compilation Process [Prasanna Ghali]
By default, the resulting assembly language is stored in file hello.s . A partial listing of the
assembly language for an Intel           (Pentium) CPU looks like this:
Notice that line      of the assembly language code above contains a call to C standard library
function printf .
The Assembler
The assembler is a translator that transforms assembly language code into machine code and
generates an object file. When there are calls to external functions in the assembly source file - as
with line      in the assembly language code - the assembler leaves the addresses of external
functions undefined, to be filled in later by the linker. The assembler is invoked with -c option of
gcc :
1 $ as hello.s -o hello.o
The resulting object file hello.o contains the machine instructions for the source code in file
hello.c , with an undefined reference to printf . Unlike other intermediate files generated by
gcc , object file hello.o is a binary file and is therefore not human-readable.
                                                       8 / 17
                              Introduction to Compilation Process [Prasanna Ghali]
The Linker
The final stage of compilation is to use the ld program to link object files to create an executable
file or binary file. In practice, an executable requires many external functions from system and C
run-time libraries. Consequently, the actual link
commands used internally by GCC are complicated:
Fortunately there is never any need to explicitly use the ld command directly. gcc can
transparently handle the entire linking process, as in:
1 $ gcc hello.o
This links object file hello.o with the C standard library. That is, it takes the printf function and
other dependent functions from the C standard library, and the machine language version of
main function defined in object file hello.o into an executable file a.out . The program can be
executed by using the pathname of the executable a.out , as in:
  1   $ ./a.out
  2   Hello World 2020!!!
  3
Alternatively, you can use the -o option to provide an other name than a.out to the executable:
                                                     9 / 17
                             Introduction to Compilation Process [Prasanna Ghali]
the math portion of C standard library is stored in a separate static library /usr/lib/x86_64-
linux-gnu/libm.a . The functions in the math library are declared in header file <math.h> .
However, again for historical reasons, gcc does not automatically link libm.a .
Consider the following source file sin.c that makes a call to external function sin in math
library libm.a :
  1   #include <stdio.h>
  2   #include <math.h>
  3
  4   int main(void) {
  5       double angle = 0.785398; // 45 degrees in radians
  6       printf("sin(%f) = %f\n", angle, sin(angle));
  7       return 0;
  8   }
  9
However, the linker throws an error when an attempt is made to generate an executable:
The problem is that the reference to function sin is neither defined in source file sin.c nor in
the default C standard library libc.a . Instead, it is defined in external math library libm.a and
the compiler does not link to file libm.a unless it is explicitly selected. This is done by using the -
lm option to the linker stage of gcc :
Option -lm is a shorthand for link object files with a library file /usr/lib/x86_64-linux-
gnu/libm.a .
                                                   10 / 17
                             Introduction to Compilation Process [Prasanna Ghali]
create the executable. The following picture illustrates the process by which multiple source files
and external libraries are combined to generate an executable.
In the following example, the implementation of algorithm                  is divided into two source files
main.c and sum_fn.c and a header file sum.h . The division of tasks to two programmers
consists of a client programmer implementing main.c that uses the implementation of algorithm
       and a second programmer independently implementing algorithm                       in source file
sum_fn.c and also providing an interface or header file sum.h . Neither programmer is aware of
nor has access to the other programmer's source files [note that header files are by design
supposed to be shared].
Here is the implementation of driver source file main.c containing the definition of function
main [recall that every C program must contain one and only one function called main which is
the CPU's entry point to the program] by the client programmer:
   1   #include <stdio.h>
   2   #include "sum.h"
   3
   4   int main(void) {
   5       int n;
   6       printf("Enter a positive natural number: ");
   7       scanf("%d", &n);
   8
   9       printf("Sum of first %d natural numbers is: %d\n", n, sum(n));
  10       return 0;
  11   }
  12
The implementation of algorithm            in the previous version of the program in source file
sum.c has been replaced by a call to a new external function sum , which from the perspective of
both the author of main.c and the compiler is defined somewhere.
Another new entry in source file main.c is the addition of preprocessor directive #include
"sum.h" on line . This is an interface file provided by function sum 's author containing its
function prototype. A function prototype specifies the function's name, its parameter list, and its
return type. The compiler will use this function prototype to check for the correct use of function
sum by the author of main.c . The compiler does this check by ensuring that the function call's
arguments and return type match up correctly with the function definition's parameters and
return type. In simpler terms, all of this means that since the compiler doesn't have access to the
definition of function sum in file sum_fn.c , it will use the function prototype in header file sum.h
to pass judgement on whether the call to function sum in main.c is correct.
                                                   11 / 17
                                 Introduction to Compilation Process [Prasanna Ghali]
Finally, notice the difference in syntax for #include directives in lines               [ #include <stdio.h> )
and       ( #include "sum.h"> ]. The delimiters < and > indicate to the preprocessor that it must
search the standard list of system directories special to the compiler toolchain being used. In the
Linux distro on DigiPen lab desktops, C standard library header files are located at
/usr/include . The delimiters " and " indicate to the preprocessor that it must search the
current directory before looking in the standard list of system directories.
Suppose header file sum.h supplied by the implementer of file sum_fn.c looks like this:
  1       int sum(int);
  2
The header file contains a single line containing the function prototype for sum .
The implementer of file main.c now has everything required to create an object file:
Independently, the second programmer has defined function sum in a separate file sum-fn.c :
      1    #include "sum.h"
      2
      3    int sum(int N) {
      4        int total = 0;
      5        for (int i = 1; i <= N; ++i) {
      6            total += i;
      7        }
      8        return total;
      9    }
  10
Notice that line       contains a preprocessor directive to include header file sum.h . This is a
recommended (and sometimes necessary) practice to ensure that both the function prototype in
the header file and definition in source file match up. The author of sum-fn.c can independently
compile and generate a corresponding object file:
Either of the two programmers or any other programmer can now link together function main in
object file main.o , function sum in object file sum-fn.o , and C standard library function printf
defined in static C standard library libc.a into a single executable, say new-sum.out :
To run executable program new-sum.out , type the pathname of the executable like this:
  1       $ ./new-sum.out
  2       Enter a positive natural number: 100
  3       Sum of first 100 natural numbers is: 5050
                                                       12 / 17
                              Introduction to Compilation Process [Prasanna Ghali]
-std=c11 : Information about the C11 standard is available in the C11 N1570 standard draft.
     -pedantic-errors : Gives an error when base standard C11 requires a diagnostic message to
     be produced. C89 allows the declaration of a variable, function argument, or structure
     member to omit the type specifier, implicitly defaulting its type to int . Although, legal in
     C89, this is considered illegal in C99, C11, and C++:
       1   #include <stdio.h>
       2   int main(void) {
       3       static x = 10;
       4       printf("x: %d\n", x);
       5       return 0;
       6   }
       7
     However, compiling this code with a C11 compiler, as in: gcc -std=c11 tester.c elicits only
     a warning message. However, compiling the same code with the -pedantic-errors option
     produces an error.
           9. The intent is that an implementation should identify the nature of, and where
               possible localize, each violation. Of course, an implementation is free to produce
               any number of diagnostics as long as a valid program is still correctly translated. It
               may also successfully translate an invalid program.
     Based on the above text, -pedantic-errors cannot be solely used to check programs for
     strict C conformance. The flag finds some non-standard practices, but not all - only those for
     which C requires a diagnostic, and some others for which diagnostics have been added.
     -Wall : This enables all the warnings about constructions that some users consider
     questionable, and that are easy to avoid [or modify to prevent the warning]. Some of them
     warn about constructions that users generally do not consider questionable, but which
     occasionally you might wish to check for; others warn about constructions that are necessary
     or hard to avoid in some cases, and there is no simple way to modify the code to suppress
     the warning. Some of them are enabled by -Wextra but many of them must be enabled
     individually. The entire list of warning flags enabled by -Wall for GCC C compiler can be
     found here.
                                                    13 / 17
                               Introduction to Compilation Process [Prasanna Ghali]
     -Wextra : This enables some extra warning flags that are not enabled by -Wall . The entire
     list can be found here.
     -Werror : Converts diagnostic messages generated by the base compiler and warnings
     generated by flags -Wall and -Wextra to errors. This is a necessary feature for generating
     cleanly compiled code that doesn't generate any warning messages.
1 return-type f();
     C89, C99, and C11 compilers read the above declaration as f is a function that takes
     unknown number of parameters with unknown types and return a value of type return-
     type . This means the following code in a source file test.c will compile and link with
     undefined behavior when executed.
           1   #include <stdio.h>
           2
           3   extern int foo();
           4
           5   int main(void) {
           6       int x = 2, y = 4, z = 6;
           7       printf("%d + %d = %d\n", x, y, foo(x, y));
           8       printf("%d + %d + %d = %d\n", x, y, z, foo(x, y, z));
           9       return 0;
       10      }
       11
       12      int foo(int i, int j) {
       13          return i + j;
       14      }
       15
     The code will compile with GCC C and Clang compilers (and also with Microsoft Compiler)
     without any diagnostic messages:
However, the same code will not compile with a C++ compiler:
     since the declaration return-type f(); in C++ compilers indicates that f is a function that
     takes no parameters and returns a value of type return-type .
     To ensure compatibility with C++ standards, the -Wstrict-prototypes must be used with
     GCC and Clang to ensure that test.c doesn't successfully compile.
                                                     14 / 17
                              Introduction to Compilation Process [Prasanna Ghali]
of source files to be recompiled. These recompilations may occur hundreds of times every day
causing substantial delays as programmers wait for the executable to be created. More
importantly, programmers will have to remember dependencies between different files. For
example, if source file b.c includes header file a.h and if a.h is updated, then b.c must be
recompiled even though it was not altered.
It can be difficult to remember the entire list of source files and the dependencies required to
create an executable from them. To solve this problem, a program called make is used. The
version of make provided by GCC is coincidentally called make . make is a facility for automated
maintenance and build executables from source files. make uses a makefile that specifies the
dependencies between files and the commands that will bring all files up to date and build an
executable from these up to date files. In short, makefile contains the following information:
A simple makefile consists of rules with each rule consisting of three parts: a target, a list of
prerequisites, and a command. A typical rule has the form:
target is the name of the file to be created or an action to be performed by make. prereq-1 ,
prereq-2 , and so on represent the files that will be used as input to create target . If any of the
prerequisites have changed more recently than target , then make will create target by
executing commands command1 , command2 , and so on. make will terminate and shutdown if any
command is unsuccessful. Note that every command must be preceded by a tab and not spaces!!!
Here's an example:
Line    says that target example.out must be remade (or made if it doesn't exist) if any of the
prerequisite files [ main.o , file1.o , file2.o ] have been changed more recently than the target.
Before checking the times prerequisite files were changed, make will look for rules that start with
each prerequisite file. If such a rule is found, make will make the target if any of its prerequisites
are newer than the target. After checking that all prerequisite files are up to date and remaking
any that are not, make brings example.out up to date.
Line    tells make how it should remake target example.out . This involves calling gcc with the
usual and required GCC options to compile and link source files main.c , file1.c , and file2.c .
A makefile can also contain macro definitions where a macro is simply a name for something. A
macro definition has the form:
1 NAME = value
                                                    15 / 17
                            Introduction to Compilation Process [Prasanna Ghali]
The value of macro NAME is accessed by either $(NAME) or ${NAME} . make will replace every
occurrence of either $(NAME) or ${NAME} in makefile with value .
Target clean on line     is different from the other targets; it has no prerequisites. If the following
command is issued in the shell:
1 $ make clean
then make will execute only the command on line in rule clean and then exit.
Let's conclude this section by writing a simple makefile called Makefile for the new_sum program
that consists of two source files main.c and sum_fn.c and a header file sum.h . The default
makefile is named makefile or Makefile ; other names can be used but make must be provided
the non-default makefile name.
                                                  16 / 17
                                Introduction to Compilation Process [Prasanna Ghali]
The most common error with a makefile is programmers forgetting to put a horizontal tab at the
beginning of a command line, and instead place space characters there. Here's what happens if
line       is prefixed with space characters rather than a tab:
                                                      17 / 17
                                    Annotated First C Programs [Prasanna Ghali]
  Everything related to C in this course refers to the C11 standard of the language. Certain code that will be
  demonstrated throughout the semester might fail to compile in older C standards.
  C programs follow the von Neumann architecture. Both instructions and data of a program reside in memory.
  Programming is then an endeavor that requires programmers to write appropriate instructions that
  transform input data into required output data.
  Source file(s) contain functions that communicate with other functions in the program by passing and
  returning values.
  A function encapsulates an algorithm. An algorithm is a finite sequence of instructions that operate on data.
  Think of a function as a black box that takes certain input, performs actions that transform the input, and
  then returns the transformed data as output to the function's caller.
  A C program is made up of functions which in turn are made up of statements. A statement is the atomic unit
  of a C program. Informally, statements in an algorithm correspond to C statements.
      1. Literals express constant values such as 7 or 123.56 or a character such as 'a' or a sequence of
        characters such as "Hello" .
      2. Variables identify named memory locations at which data of interest is located. There are two values
        associated with variables. The first is the physical memory address that variables represent. The second
        is the contents of these physical memory locations. Unlike other high-level programming languages,
        both the address and the value stored at the address are accessible to C programmers.
  All data, represented by both constants and variables, is typed. A data type specifies the set of values and the
  set of operations that can be applied on these values. The type specified by a programmer for a constant or a
  variable allows the compiler to translate to the machine the nature of the data stored and how the machine is
  to interpret the data. If a variable doesn't have a type associated with it, it will be impossible for C compilers
  to convey to the machine how to correctly interpret the contents of the memory locations associated with
  that variable. For this reason, both C and C++ are said to be statically typed languages. On the other hand,
  Python is an example of a dynamically typed language.
  Using decimal notation is natural for ten-fingered humans, but the language of a computer, called machine
  language, is a sequence of s and s. Each of the digits,      and , is called a binary digit or bit. A bit can be only
  a   or a   - never anything else, such as   or ,   or   or    or   . This is a fundamental concept. Every piece of
  information stored in a computer or processed by a computer, whether it is your name, or your street
  address, or the amount you owe on your credit card, is stored as strings of s and s.
  In isolation, a single bit is not very useful since it can represent only two values. When groups of bits are
  combined together and some interpretation is applied that gives meaning to the different possible bit
  patterns, it becomes possible to represent the elements of any finite set. A sequence of bits is referred to as a
  binary number. For example, using a binary number system, groups of bits can be used to encode integers. By
  using a standard character code such as ASCII, the letters and symbols on a keyboard can be encoded as
  binary numbers to represent text in a document.
  Although humans can represent arbitrarily large numbers using the decimal, or octal, or some other number
  system, machines are only capable of representing binary numbers having specific number of bits. Machines
  don't let you collect together or process binary numbers having an arbitrary number of bits. Instead,
  machines represent instructions and data using binary numbers having certain fixed number of bits. Since
                                                      1 / 21
                                         Annotated First C Programs [Prasanna Ghali]
the early days of computing, a sequence of eight bits, called a byte, has become the de facto standard for an
unit of digital information. A byte represents the smallest data item and the unit of storage in modern
computers.
CPUs have evolved from              bits to incorporate binary numbers having       ,   , and   bits. In addition, every
CPU has a word size, indicating the number of bits in a binary number that can be atomically [that is, as a
single unit] processed by the CPU. Most modern CPUs have a                   bit word size. Currently, for each specific bit
size [ ,     ,     , and        bits], computers specify binary numbers using unsigned, signed, and floating-point
representations:
     Unsigned representation for positive integers greater than or equal to              encoded in traditional binary
     form. For          bits,             unsigned numbers ranging from        to       can be represented. For       bits,
                            unsigned numbers ranging from       to         can be represented. And so on for           and
            bits.
     Signed representation for both positive and negative integers is encoded in two's-complement form. For
           bits,                 signed numbers ranging from          to      can be represented. For        bits,
                            signed numbers ranging from               to         can be represented. And so on for
     and            bits.
     Floating-point representation for rational numbers of the form                          encoded in the IEEE 754
     format.
The fundamental, numeric data types for                bit C11 compiler used in this course are:
Note that types signed short int , signed int , signed long int , and signed long long int are
equivalent to abbreviated types short , int , long , and long long , respectively. Similarly, unsigned short
int , unsigned long int , and unsigned long long int are equivalent to abbreviated types unsigned
short , unsigned long , and unsigned long long , respectively.
In programming languages, the term identifier means the name given to variables, functions, macros, and so
on. Except literals, everything in a C program such as variables and functions must have an identifier so that
they can be uniquely identified by programmers and compilers.
Before a variable or function is used in a program, their identifiers must first be declared to the compiler, and
presumably to any human reader of the program. More specifically, the compiler must be provided with the
type associated with the identifier. This allows the compiler to correctly translate to the machine the values
represented by these identifiers. Note that ISO C11 standard specifies that variables can be declared
anywhere in a function with the only caveat that they be declared before their first use.
By default, every program is provided three input/output streams to interact with its environment: standard
input [ stdin ] for the program to read input from the keyboard device by default, standard output [ stdout ]
for the program to write output to the computer display screen by default, and standard error [ stderr ] for
the program to write error or diagnostic messages to the computer display screen by default.
Before continuing with this document, you must understand how compilers work. Compilation is a multi-
stage process involving several tools, including the compiler itself gcc , the assembler as , and the linker ld .
The complete set of tools used in the compilation process is known as the compiler toolchain or compiler
driver. The sequence of commands executed by a single invocation of gcc consists of the following stages:
                                                           2 / 21
                                          Annotated First C Programs [Prasanna Ghali]
      This course will use the ISO C11 standard. Code presented in this document and throughout this semester
      may not compile in older C standards.
  1. The double slash // on line        begins a single-line comment that extends to the end of the line. A comment is
      for consumption by the human reader and not the compiler. The preprocessor will strip away comments and
      replace them with single space character. This means that the compiler proper will never see comments in a
      source file.
            Line     consists of three identifiers int , main , and void . An identifier is a sequence of characters used
            to denote names of variables, functions, and other entities such as macros and types. An identifier may
            contain letters, digits, and underscores, but must begin with a letter or underscore. This page provides
            information and rules specific to C identifiers.
            Not only are int and void identifiers, they're also C keywords. A keyword is a predefined identifier that
            has special meaning to C compilers.
            Line     declares function main . Every C program uses function main as the entry point to the program
            and therefore there can only be one and only one function called main in a C program.
            Recall that a function encapsulates an algorithm that transforms input value(s) to output value(s). Inputs
            to a function are specified between a pair of parentheses ( and ) as a sequence of comma-separated
            values called function parameters. Function main takes a single parameter of type void and returns a
            value of type int . Although functions can take as many parameters as dictated by the author, they can
            only return a single value.
            Identifier void is a C keyword indicating it is a C data type specifying no value. The use of void data
            type in the current context where it is delimited within parentheses ( and ) indicates to the compiler
            and human readers that function main won't receive any data, or value, or information from the
            function that invoked it.
            C++ standards allow programmers to skip the use of void in function parameters. That is, C++
            compilers will implicitly assume that function main doesn't receive input values and has a void
            parameter if the function is written as:
            However, C11 requires every function that doesn't receive input values to specify this fact to the
            compiler using void . Therefore, the above code will not compile with the C compiler and must be
            rewritten as
                                                            3 / 21
                                         Annotated First C Programs [Prasanna Ghali]
          int is a C keyword indicating a data type that on both          bit and      bit machines represents    bit
          signed integers ranging in value from                     (      ) to             (       ). In the current
          context, the program's author is indicating to the compiler that function main will return a value of type
          int to the function that invoked it. Recall that type int is an abbreviated and equivalent form of the
          wordier type signed int .
          To summarize, line    of the source text declares identifier main to be a function that takes no values and
          returns a value of type int to the operating system.
3. Line :
          Curly braces are used in C to group together stuff including all statements required to implement an
          algorithm.
          Left curly brace { starts the function body or code block of function main and will contain statements
          that implement the algorithm encapsulated by function main . The right curly brace on line         } matches
          the left curly brace and ends the body of function main .
4. Line    contains a C statement.
          Notice that statement(s) within a function are indented to easily identify to human readers that these
          indented statements constitute a code block. Unlike Python, C and C++ are free form and programmers
          have very few restrictions on how they present source code to compilers.
          All statements are delimited by a semi-colon ; . Here, statement return 0; will result in function main
          [and therefore the program] returning value 0 of type int to the operating system indicating that the
          program executed successfully. Note that the type of the value returned by the return statement
          [literal 0 has type int ] matches the return type [ int ] specified on line .
          C programs return nonzero values to indicate failure. Not every operating system makes use of that
          return value: Linux-based operating systems do, but Windows systems rarely do.
Add return to your list of C keywords - the others are int and void .
          C11 and all standards of C++ allow programmers to skip the explicit return statement in function main .
          If there is no explicit return statement in function main , these C/C++ compilers will implicitly add
          statement return 0; to indicate successful completion. This means that the most minimal C/C++
          program will look like this:
            1   int main(void)
            2   {
            3   }
            4
          For consistency with older C standards, my documented examples will always contain an explicit return
          statement.
5. Line contains an empty line. According to ISO C standards, every source file must terminate with a newline.
6. C is a free form language implying that programmers have very few restrictions on how they present source
  code to compilers. For example, the entire source code in nothing.c can be written on a single line:
                                                           4 / 21
                                        Annotated First C Programs [Prasanna Ghali]
    Writing code like this decreases the vertical spread of the source code while increasing its horizontal spread.
    Jamming several things into a single line makes code hard to read and maintain for programmers. Instead, I
    prefer a compromise that decreases vertical spread a little bit while increasing horizontal spread a little bit.
    My code will follow this template:
  7. Open a Windows command prompt. Change your current working directory to C:\sandbox . Switch to Linux
    bash shell using Window shell command wsl . Open Code from the bash shell using command: code
    nothing.c . Use Code to enter the code described in nothing.c . After saving the file, use GCC C compiler
     gcc to compile nothing.c (note that the $ symbol below represents the Linux bash shell command prompt
    and is not part of the gcc command):
           The six options to gcc : -std=c11 , -pedantic-errors , -Wstrict-prototypes , -Wall , -Wextra , -Werror
           are required and necessary every time you compile a source file.
           Option -c indicates that source file nothing.c is only to be compiled but not linked. That is, source file
           nothing.c is converted to an object file containing binary machine code for a specific CPU but not into
           an executable program.
           Option -o nothing.o gives the name nothing.o to the output object file generated by the compiler. All
           though compilers will default the object file's name to the name of the source file with an extension of
           .o , I explicitly specify the name of the object file.
Link object file nothing.o with standard library object files to create an executable:
           Since this particular example describes a minimal C program, there are no C standard library object files
           to be linked to the object file nothing.o . If option -o is not used, the linker will default the executable
           file to a.out .
To run executable program nothing.out , type the executable's pathname like this:
             1     $ ./nothing.out
             2     $
           Repeat the compile and link steps using verbose option -v . This option prints the commands that
           execute the different compilation stages to standard output.
                                                            5 / 21
                                        Annotated First C Programs [Prasanna Ghali]
 1     #include <stdio.h>
 2
 3     /*
 4     Print a greeting to the world!!!
 5     */
 6     int main(void) {
 7         printf("Hello World!!!\n");
 8
 9         return 0;
10     }
11
1. Let's start with line containing unusual characters # , < , and > : #include <stdio.h>
            The preprocessor is a program used by the C compiler to provide certain text utility functionalities. Think
            of the C preprocessor's behavior and capabilities as being similar to a specialized text editor.
            Identifier include is a directive to the preprocessor to replace line     with contents of file stdio.h .
            Delimiters < and > tell the preprocessor to begin searching for file stdio.h in standard include paths
            that were established when the compiler was installed on a computer. The search will conclude in the
            current working directory of source file hello.c .
            What is the purpose behind including file stdio.h ? This file is supplied by the compiler vendor and
            contains declarations of input and output functions defined in C standard library. Recall that C itself is a
            fairly small language and it is up to the C standard library to provide input/output capabilities to C
            programs. Specific to source file hello.c , stdio.h contains a declaration of function printf that
            prints text to stdout . Files such as stdio.h are called header files because C requires identifiers be
            declared before their first use and related identifiers are collected in a file which is conveniently added at
            the head or top of the source file so that these identifiers are visible throughout the source file.
            A function declaration introduces a reference to a function defined elsewhere (in this case, in the C
            standard library) by specifying the function's name, its parameter list, and its return type. A declaration
            for function printf is required in source file hello.c for the compiler to ensure the call to printf
            matches the number and types of parameters in the declaration of printf and further ensure that the
            return value from printf is used correctly by the caller in hello.c . Note that the code in hello.c
            ignores the return value from function printf . In short, the compiler will use the function declaration of
            printf to check for the correct use of function printf in source file hello.c .
            Function declarations as discussed in this document and throughout this course are known as function
            prototypes to distinguish them from an older style of function declarations in which the parameter list is
            left empty. This course will leave this bit of ugly history behind and instead follow C++ terminology: the
            terms function declaration and function prototype are considered synonyms and the term function
            declaration will be used in lieu of function prototype.
2. Line      is a newline which is left untouched by the preprocessor. The space, tab, and newline are collectively
     known as whitespace characters. These characters are ignored [there are a few cases where they're not
     ignored but let's not dwell on those obscure details at this early stage] and their main purpose is to provide
     punctuation.
3. Lines , , and :
            Lines , , and    specify a multi-line comment. A multi-line comment is program text delimited by
            characters /* and characters */ . A multi-line comment can be on a line by itself, or it can be on the
            same line as a statement, or can extend over several lines.
            Comments are only meant for consumption by human readers - they're supposed to provide the reader
            with a clear and easy-to-understand description of what is the algorithm and how the algorithm is being
            implemented by sequences of statements. Although comments are optional, good style requires
            comments be used throughout a program to improve its readability and to document the algorithm.
            Since comments don't have meaning to a compiler, C standards require the preprocessor to strip the
            source file of comments by replacing them with single space characters.
4. Line :
            The declaration of function main has been seen in an earlier program. Now, let's expand on the concept
            of declarations by introducing definitions. Line   begins the declaration and also the definition of function
            main .
                                                           6 / 21
                                       Annotated First C Programs [Prasanna Ghali]
          Think of a function definition as the physical manifestation of what is described in a function declaration.
          While a function declaration tells the compiler [and presumably human readers] about the function's
          name, list of function parameters, and type of value returned by the function, a function definition creates
          memory storage for the instructions necessary to implement the algorithm that is encapsulated by the
          function and defines its parameters and return value. The following code snippet illustrates the
          difference between a function declaration and function definition:
                1   /*
                2   this is a function declaration (prototype): it tells the
                3   compiler that inc is a function that takes a parameter of
                4   type int and returns a value of type int
                5   */
                6   int inc(int x);
                7
                8   /*
                9   this is a function definition: it not only tells the compiler
            10      that inc is a function that takes a parameter of type int and
            11      returns a value of type int; in addition a function definition
            12      implements the function using statements.
            13      */
            14      int inc(int x) {
            15          return x+1;
            16      }
            17
          All C programs must define a single function named main . This function will become the entry point of
          the program - that is, main will be the first function executed when the program is started. Returning
          from this function terminates the program, and the returned value is treated as an indication of program
          success or failure.
          Any time you want to group things in C you put these things between opening curly brace { and closing
          curly brace } . Compilers understand these braces as punctuator symbols that enclose these things. With
          functions, the statements implementing an algorithm are the things that must be enclosed between {
          and } . Notice that unlike previous programs, left curly brace { is not present in its own line but is
          instead separated from closing parenthesis ) by whitespace. All subsequent statements until a
          corresponding right curly brace } specify the function's body. In fact, left curly brace { need not be
          separated from the closing parenthesis ) by whitespace nor does the first statement have to be
          whitespace separated from the preceding { :
            1       #include <stdio.h>
            2       /*Print a greeting to the world!!!*/
            3       int main(void){printf("Hello World!!!\n");return 0;}
            4
          C is a free form language that only requires whitespace to provide punctuation. For example, on line      of
          the above code, the compiler will require a whitespace between int and main to distinguish these two
          discrete identifiers. Otherwise, intmain will be interpreted as a single identifier.
            1       #include <stdio.h>
            2       /*Print a greeting to the world!!!*/int main
            3       (void){printf("Hello World!!!\n");return 0;}
            4
          There doesn't need to be whitespace between { and printf because the compiler understands { to
          be a punctuator symbol that indicates the start of a new block of code and the subsequent identifier
          printf is considered as part of the first statement in this new block of code.
                                                         7 / 21
                             Annotated First C Programs [Prasanna Ghali]
Since identifier printf is followed by left parenthesis ( , followed by a bunch of stuff, followed by right
parenthesis ) , the compiler will understand that function printf is being called. This function is
defined in the C standard library and is used for printing formatted data to standard output.
Between the left and right parentheses, the text enclosed in a pair of double quotes "Hello
World!!!\n" is called a string literal. A string literal is a sequence of characters delimited by a pair of
double quotes " .
The string literal "Hello World!!!\n" is the argument or value passed to function printf .
You might expect the sequence of characters Hello World!!!\n to be printed to stdout by function
printf . However, that is not the case - only the sequence of characters "Hello World!!!" are printed
to stdout on the first line followed by a newline. The backslash '\' is called an escape character when it
is used in a string. The compiler combines it with the character that follows it and then attaches a special
meaning to the combination of characters. For example, \n represents a skip to newline. The cursor is a
moving place marker that indicates the next position in stdout [on the screen, for example] where
information will be displayed. When executing a printf function call, the cursor is advanced to the start
of the next line in stdout if the \n escape sequence is encountered in the string passed to the function.
A printf string often ends with a \n newline escape sequence so that the call to printf produces a
completed line of output. If no characters are printed on the next line before another newline character
is printed, a blank line will appear in the output. For example, the calls
The first call to printf places the cursor at the start of line . Since \n newline escape sequence is the
first character of the string in the argument to the second call to printf , the cursor will move to the
start of line . Because the second call to printf also terminates with \n , the cursor will print the
characters tomorrow will be a better day. on line           and then shift to the start of line .
In addition to \n , a number of additional escape characters are recognized. For example, the sequence
\\ is used to insert a single backslash in a string, and the sequence \" will insert a double quote in a
string. Thus, the call to function printf :
1 printf("\"The End.\"\n");
1 "The End."
In short, function main is calling function printf with string literal "Hello World!!!\n" as argument
that is printed to stdout by printf as a line containing Hello World!!! followed by a newline.
                                                8 / 21
                                      Annotated First C Programs [Prasanna Ghali]
 6. Line   represents a newline that was introduced by the programmer to make the code more readable to
   other human readers. As indicated earlier, a newline is left untouched by the preprocessor.
 7. Line   contains statement return 0; which indicates that function main is returning a value         of type int .
   Since the definition of function main on line     indicates that main is a function that takes no value and
   returns a value of type int , the function must return a value of type int .
 8. Line    contains right curly brace } which matches left curly brace { on line      indicating the end of the body
   of function main .
9. Line is empty because every C source file is required to terminate with a newline.
10. Compile source file hello.c using GCC C compiler with the full suite of options:
11. Link object file hello.o with C standard library to create executable file hello.out :
12. To run executable program hello.out , type the executable's pathname like this:
      1    $ ./hello.out
      2    Hello World!!!
      3
 2. What happens when you add characters /* at the beginning and characters */ at the end of line            in the
   above code?
3. What happens when you add characters // at the beginning of line in the above code?
   It is clear that C11 prohibits the nesting of multi-line comments. However, single-line comments can be
   nested inside multi-line comments.
 4. Compile the source file after commenting line ? Does the compiler generate diagnostic messages? Do you
   understand why the compiler doesn't generate diagnostic messages?
 2. Since function hello will be used by other parts of the program and function hello in turn calls C standard
   library function printf , a header file hello-decl.h is created to declare these two functions. This is the
   purpose of header files - to gather together declarations of related entities in a file and provide clients the
   service of including this header file rather than having to individually declare each entity. More specifically,
   line    in the following header file contains the declaration of function hello . As described earlier, a function
   declaration specifies the function's name, its parameter list, and its return type. The compiler will use this
   function declaration to check for the correct use of function hello by clients that wish to use this function in
   their source files. File hello-decl.h will look like this:
                                                        9 / 21
                                     Annotated First C Programs [Prasanna Ghali]
    1       #include <stdio.h>
    2
    3       // declaration (prototype) of function hello
    4       void hello(void);
    5
3. Source file hello-defn.c containing the definition of function hello will look like this:
    1       #include "hello-decl.h"
    2
    3       // definition of function hello
    4       void hello(void) {
    5           printf("Hello World!!!\n");
    6       }
    7
  Notice that line     of source file hello-defn.c contains a preprocessor directive to include header file hello-
  decl.h . This is a recommended practice to ensure that both the function declarations in the header file and
  their definitions in the source file match up. Also notice that line   has an include directive that delimits the
  name of the header file hello-decl.h between a pair of double quotes " . When the header file is delimited
  by angle brackets <> , the preprocessor will search for the header file in the standard include paths of the
  compiler. Now, with a pair of double quotes " used as delimiters, the preprocessor will only search for the
  header file in the current directory in which source file hello-defn.c is located.
  The author of file hello-defn.c now has everything required to successfully compile the source file to an
  object file:
4. Independently, the second programmer has defined function main in a separate file driver.c :
    1       #include "hello-decl.h"
    2
    3       int main(void) {
    4           hello();
    5
    6           return 0;
    7       }
    8
  Similar to source file hello-defn.c , driver.c has an include directive on line        that delimits the name of
  header file hello-decl.h between a pair of double quotes " . When hello-decl.h is included in a source file
  such as driver.c , the preprocessor will replace the line containing include directive with contents of file
  hello-decl.h . The transformed driver.c will look like this:
        1   #include <stdio.h>
        2
        3   void hello(void);
        4
        5   int main(void) {
        6       hello();
        7
        8       return 0;
        9   }
    10
                                                       10 / 21
                                      Annotated First C Programs [Prasanna Ghali]
   The preprocessor will notice that the transformed version of driver.c again contains an include directive
   and will further transform the previously transformed file by replacing line     of transformed driver.c with
   the contents of file stdio.h . This process will recursively continue if stdio.h itself contains include
   directives. The transformed version driver.c will look like this:
   The author of file driver.c now has everything required to create an object file without access to the source
   file containing the definition of function hello :
 5. Either of the two programmers or any other programmer can now link together function main in object file
   driver.o , function hello in object file hello-defn.o , and C standard library function printf defined in
   static C standard library libc.a into a single executable, say new-hello.out :
6. To run executable program new-hello.out , type the executable's pathname like this:
     1       $ ./new-hello.out
     2       Hello World!!!
     3
 7. One way to think of hello-decl.h and hello-defn.c is that hello-decl.h is an interface file while hello-
   defn.c is an implementation file. Other programmers include interface files in their source files to call
   functions declared in these interface files without either programmers nor compilers aware of the
   implementation details of these functions. Instead programmers and compilers are only interested in
   whether these declared functions are referenced or called correctly in these other source files. It is the linker
   that will ensure that the implementation details of these declared functions are integrated with the functions
   in these other source files to create a synergistic and whole execution file.
Things to try:
 1. What happens when you try to compile driver.c by commenting out line ?
   If line    of driver.c is removed, that is, if driver.c doesn't include header file hello-decl.h , the compiler
   will implicitly assume that function hello is declared as:
     1       int hello();
     2
   This declaration says that hello is a function that takes an unknown number of parameters and returns an
   int . That is, if the declaration of function hello is not present in the source file, the compiler will implicitly
   assume that hello is declared as int hello(); and print a diagnostic message to indicate this assumption:
                                                        11 / 21
                                     Annotated First C Programs [Prasanna Ghali]
   Notice that source file driver.c is successfully compiled into object file driver.o . In fact, this object file
   driver.o can be linked with object file hello-defn.o and C standard library to create an executable that
   prints the required greeting to stdout :
   All though the executable seems to run correctly, remember that the compiler has made a spurious
   assumption in the absence of an explicit declaration of function hello that hello is a function that takes an
   unknown number of parameters and returns an int even though hello is defined as a function that takes
   zero parameters and returns nothing. This particular behavior of C means that it is possible to create runtime
   security holes in the program by authoring functions that call function hello with arguments. C++ designers
   correctly identified this drawback of C as a serious security threat and therefore C++ was designed to flag
   omissions of function declarations as errors. To ensure C compilers can compile C code developed many
   decades earlier, C standards are unable to flag omissions of function declarations as errors.
   The C code created in this course must compile cleanly with C++ compilers and thus the code must explicitly
   avoid certain drawbacks of C standards. Therefore, it is important that you always declare every function you
   use in a source file before its first use so that the compiler is not allowed to make implicit assumptions that
   can cause runtime bugs and security holes. You enforce this policy using gcc compiler option -pedantic-
   errors which will prevent such implicit declarations to be just passed off with diagnostic warnings:
   Notice how option -pedantic-errors has converted a diagnostic warning to an error, thereby preventing the
   object file from being created.
 2. In the previous question, you saw an example of compiler error. To distinguish between compiler errors and
   linked errors, compile and link driver.c using option -Werror like this:
   What happens when you replace the pair of double quotes delimiters #include "hello-decl.h" in line                of
   driver.c with angled braces < and > , as in #include <hello-decl.h> ?
 3. Likewise, what happens when you replace the angled brace delimiters #include <stdio.h> in line            of
   hello-decl.h with pair of double quotes delimiters #include "stdio.h" ?
                                                       12 / 21
                                       Annotated First C Programs [Prasanna Ghali]
Arithmetic expressions that solve science and engineering problems often require computations beyond basic
addition, subtraction, multiplication, and division. Much problem solving requires the use of exponentiation,
logarithms, exponentials, and trigonometric functions. This section introduces mathematical functions available in
the C standard library.
The process begins with the use of the following preprocessor directive in any source file referencing
mathematical functions in the C standard library:
1 #include <math.h>
This directive specifies that function prototypes and macros be added to the source file to aid the compiler when it
converts calls to mathematical functions in the C standard library.
If your algorithms involve extensive math operations then you should look up the wide variety of functions
prototyped in math.h to see which functionality is already implemented and what you may have to build from
scratch. There's an important detail relating to trigonometric functions that stymies beginner programmers:
trigonometric functions assume that their argument is in radians. For example, if you've a variable theta
containing a value in degrees, that angle must be converted to radians (recall from trigonometry that
radians). The following code fragment does the trick:
  1       #define PI            (3.141593)
  2       #define DEG_TO_RAD    (PI/180.0)
  3       ...
  4       double theta_rad = theta * DEG_TO_RAD;
  5       double x = sin(theta_rad);
  6       // conversion can also be specified within function reference
  7       double y = sin(theta * DEG_TO_RAD);
First, an include preprocessing directive for math.h and function prototype for function distance are provided
in header file distance.h :
      1   #include <math.h>
      2
      3   /*!
      4   @author pghali
      5   @brief    Computes the distance between two points.
      6
      7   This function takes coordinates of point (px, py) and
      8   point (qx, qy) and returns the distance between P and Q.
      9
  10      @param px - double-precision floating-point value specifying px.
  11      @param py - double-precision floating-point value specifying py.
  12      @param qx - double-precision floating-point value specifying qx.
  13      @param qy - double-precision floating-point value specifying qy.
  14      @return      - a double-precision floating-point value measuring the
  15      distance between P and Q.
                                                         13 / 21
                                          Annotated First C Programs [Prasanna Ghali]
  16      *//*_____________________________________________________________*/
  17      double distance(double px, double py, double qx, double qy);
  18
  1       #include "distance.h"
  2
  3       double distance(double px, double py, double qx, double qy) {
  4           // compute sides of right triangle formed by two points
  5           double width   = qx - px;
  6           double height = qy - py;
  7           return sqrt(width*width + height*height);
  8       }
  9
Function distance can be tested by calling it from function main which is implemented in file test-dist.c :
      1   #include <stdio.h>
      2   #include "distance.h"
      3
      4   int main(void) {
      5       double px = 0.0, py = 0.0, qx = 3.0, qy = 4.0; // input portion
      6       // compute distance from P(0, 0) to Q(3, 4)
      7       double dist = distance(px, py, qx, qy);
      8       printf("Distance is %f\n units", dist); // output portion
      9       return 0;
  10      }
  11
However, the linker throws an error when an attempt is made to generate an executable:
The problem is that function sqrt is not defined in the default C standard library libc.a . Instead, it is defined in
external math library libm.a and because of historical reasons the compiler does not link to file libm.a unless it
is explicitly selected. This is done using -lm option to the linker stage of gcc :
Option -lm is a shorthand for link object files with library file /usr/lib/x86_64-linux-gnu/libm.a .
                                                            14 / 21
                                       Annotated First C Programs [Prasanna Ghali]
  1   $ ./test-dist.out
  2   Distance is 5.000000 units
  3
The two source files distance.c and test-dist.c can be individually compiled and then linked together along
with the C standard library with a single call to gcc :
This printf statement contains two arguments: a format string and a print list containing an identifier to specify
the value to be printed.
A format string is enclosed in a pair of double quotes " , and can contain text, format specifiers, or both. A format
specifier begins with the character % and describes the format to use in printing the value of a variable. If the
format string doesn't contain format specifiers, the characters in the format string will be printed to stdout as is.
In this example, the format string specifies that the characters Distance is are to be printed. The next group of
characters %f represents a format specifier that indicates that a floating-point value is to be printed next, which
will then be followed by the characters units . The next combination of characters \n represents a newline
indicator; it causes a skip to a newline on stdout after the information has been printed. The second argument in
the printf statement is a variable dist ; it is matched to the format specifier %f in the format string. Function
printf is authored to a print a float or a double when the format specifier is %f [floating-point form]. Thus, in
this example, since the value of dist is      , this value will be printed to stdout :
Why does printf print 5.000000 and not 5.0 ? This matter will be explained in the next section.
                                                          15 / 21
                                         Annotated First C Programs [Prasanna Ghali]
       Format specifiers f and F always prints at least one digit to the left of the decimal point. Values displayed
       with format specifiers f and F print     digits of precision to the right of the decimal point by default. This is
       the reason why printf prints 5.000000 and not 5.0 in the previous example.
       Format specifiers e and E display floating-point values in exponential notation - the computer equivalent of
       scientific notation used in math. For example, the value              is represented in scientific notation as
                         and in exponential notation as                    by the computer. This notation indicates that
                  is multiplied by    raised to the second power (         ) where     stands for exponent. Format
       specifiers e and E print lowercase e and uppercase E , respectively, preceding the exponent, and print
       exactly one digit to the left of the decimal point. Values displayed with format specifiers e , and E print
       digits of precision to the right of the decimal point by default.
       Format specifier g [or G ] prints in either e (or E ) or f format with no trailing zeros. For example,
       is printed as 1.234 . The details of which format is picked are too detailed for beginners and the interested
       reader can look up the details here.
                                                           16 / 21
                                      Annotated First C Programs [Prasanna Ghali]
Notice that the E , e , g , and G format specifiers cause the value to be rounded when printed to stdout while
format specifier f does not.
                                                        17 / 21
                                          Annotated First C Programs [Prasanna Ghali]
Notice that the minus sign prints on line , while the plus sign is suppressed on line . Also, format specifier i on
line       behaves the same as format specifier d on line . Also, on line       , format specifier u interprets value
           as unsigned value               . The printf statements print the following text to stdout :
                                                            18 / 21
                                       Annotated First C Programs [Prasanna Ghali]
      1   #include <stdio.h>
      2   #include "distance.h"
      3
      4   int main(void) {
      5       double px = 0.0, py = 0.0, qx = 3.0, qy = 4.0; // input portion
      6       double dist = ; // compute distance
      7       printf("Distance from (%f, %f) to (%f, %f) is %f\n units",
      8                          px, py, qx, qy, distance(px, py, qx, qy));
      9       return 0;
  10      }
  11
Since there are five format specifiers in the format string, five corresponding variables or expressions must follow
in the print list. The first format specifier corresponds to variable px , the second specifier corresponds to variable
py , and so on. Because values displayed with format specifier f print      digits of precision to the right of the
decimal point by default, the text printed to stdout will be:
The new version of function main in source file test-dist-new.c looks like this:
      1   #include <stdio.h>
      2   #include "distance.h"
      3
      4   int main(void) {
      5       // input portion
      6       double px, py, qx, qy;
      7       printf("Enter point P: ");
      8       scanf("%lf %lf", &px, &py);
      9       printf("Now, enter point Q: ");
  10          scanf("%lf %lf", &qx, &qy);
  11
  12          // call to function distance
  13          double dist_pq = distance(px, py, qx, qy);
  14
  15          // output portion
  16          printf("Distance from P(%.3f, %.3f) to Q(%.3f, %.3f) is %.3f\n",
  17                 px, py, qx, qy, dist_pq);
  18          return 0;
  19      }
  20
Consider the call to scanf function on line : scanf("%lf %lf", &px, &py) . The first argument of the scanf
function is a format string "%lf %lf" that specifies the types of variables whose values are to be entered from
stdin [keyboard]. The entire (and complex) list of type specifiers is provided here. A simpler list of type specifiers
is shown in the following table:
                                                         19 / 21
                                        Annotated First C Programs [Prasanna Ghali]
From the table, the specifiers for an int variable are %i or %d ; the specifiers for a float variable are %f , %e ,
and %g ; and the specifiers for a double variable are %lf , %le , and %lg . It is critical to use the correct specifier -
don't expect help from the compiler if you use %f specifier to read the value for a double variable - your program
will fail miserably!!!
The remaining two arguments in scanf function are memory locations that correspond to the specifiers in the
control string. These memory locations are indicated with address operator & . This operator is a unary operator
[meaning it requires a single operand] that determines the memory address of the operand with which it is
associated. A common error is to omit the address operator for identifiers.
Since the values to be entered through stdin (the keyboard) are double-precision floating-points to be stored in
variables px and py , the two arguments are &px and &py . Since the program must read two values, the
numbers must be separated by at least one whitespace character which could be a space character or a tab or a
newline. Note that the number may contain a decimal point, but doesn't have to.
In order to prompt the user to enter the values, a scanf statement is preceded by a printf statement that
describes the information that the user should enter from the keyboard:
Compile this source file, link with distance.o and the math library to create an executable:
Run the executable program and the interaction with the user looks like this:
  1    $ ./test-dist-new.out
  2    Enter point P: 10.12 12.10
  3    Now, enter point Q: 13.45 45.13
  4    Distance from P(10.120, 12.100) to Q(13.450, 45.130) is 33.197
  5    $
Things to review
   1. What is an identifier? What is the legal way to write an identifier?
   2. What is a keyword? List the keywords you've come across in this document.
   3. What is a function?
   4. What is the difference between a function declaration [or function prototype] and a function definition?
   5. What are function parameters?
   6. How do functions specify that they will not take any parameters? How do functions specify that they're not
      returning values?
   7. What is the purpose of function main in a C program?
   8. What is a C comment? How many different ways can you comment a C source file?
   9. What is the preprocessor?
 10. What are whitespace characters? What purpose do whitespace characters serve?
 11. What is a data type in the context of a programming language?
 12. What is a variable?
                                                          20 / 21
                                      Annotated First C Programs [Prasanna Ghali]
13. What is a literal value? How does it differ from a variable? What is a string literal? What are the other literals in
   this tutorial?
14. Using function printf how will you print values of type int and values of type double ?
15. Using function scanf how will you print values of type int and values of type double ?
16. What does a compiler do? What is the input to a compiler and what is its output?
17. What is the purpose of a linker? What are its inputs and what does it generate as output?
                                                         21 / 21
HIGH-LEVEL PROGRAMMING I
Intro to C Programming (Part 1/3) by Prasanna
Ghali
    Outline
2
                             r0
                                          Memory
                             r1
                    ALU
                             r2
                             r3
                       Control Unit
                                         I/O Devices
                     Processor/CPU
    Stored-Program Computer (1/4)
7
                         Reference
    Stored-Program Computer (2/4)
8
                           Processor/CPU
                                                   Memory
    Stored-Program Computer (3/4)
9
PC
                  r0       Instructions
                  r1                           Data
         ALU
                  r2
                  r3
                           Memory
            Control Unit
                                 I/O Devices
          Processor/CPU
     Stored-Program Computer (4/4)
10
Memory
                   PC       Accounting program
                                                 Data
                              (machine code)
                   r0
                              Editor program
                                                 Data
                   r1         (machine code)
          ALU
                   r2          Web browser
                                                 Data
                              (machine code)
                   r3
                                   …             Data
                                   …             Data
           Processor/CPU
     Bits
11
       sequences of 0s and 1s
          Low  voltage represents 0 while high voltage
           represents 1
          Each   of 0 or 1 digit is called binary digit or bit
        This is fundamental concept - computers can only
         store and process information as strings of 0s
         and 1s
       Bits and Bytes
12
              7     6       5   4   3   2      1     0
               1    1       1   1   1   1       1     0
               999
     Computer Memory Capacity
14
                                  Size (Bytes)
        Name     Symbol
                          Exponential Explicit
      Kilobyte     KB     210 bytes   1024
      Megabyte    MB      220 bytes   1,048,576
      Gigabyte    GB      230 bytes   1,073,741,824
      Terabyte     TB     240 bytes   1,099,511,627,776
     What is Data Type?
15
          Floating-point
     Integer Data Types (1/2)
17
                                           Reference
      Instruction Set Architecture (1/2)
26
                            x = 5
     Code snippet in some   y = 3
     machine language       z = x + y
PC
                r0
                r1
         ALU
                r2
                r3
                            x = 5
     Code snippet in some   y = 3
                            z = x + y        Code snippet
     machine language
                                             transferred to
                                             memory
                PC
                              x=5
                r0
                              y=3
                r1
         ALU                  z=x+y
                r2            …
                r3            Instructions       Data
              PC
                           x=5              5      x
              r0       5
                           y=3                     y
              r1                                   z
       ALU                 z=x+y
              r2           …                …
              r3           Instructions     Data
              PC
                           x=5              5      x
              r0       3
                           y=3              3      y
              r1                                   z
       ALU                 z=x+y
              r2           …                …
              r3           Instructions     Data
              PC
                           x=5              5      x
              r0       3
                           y=3              3      y
              r1                                   z
       ALU                 z=x+y
              r2           …                …
              r3           Instructions     Data
              PC
                           x=5              5      x
              r0       5
                           y=3              3      y
              r1                                   z
       ALU                 z=x+y
              r2           …                …
              r3           Instructions     Data
              PC
                           x=5              5      x
              r0       5
                           y=3              3      y
              r1       3
       ALU                 z=x+y                   z
              r2           …                …
              r3           Instructions     Data
              PC
                           x=5              5      x
              r0       5
                           y=3              3      y
              r1       3
       ALU                 z=x+y                   z
              r2           …                …
              r3           Instructions     Data
              PC
                           x=5              5      x
              r0       5
                           y=3              3      y
              r1       3
       ALU                 z=x+y                   z
              r2       8   …                …
              r3           Instructions     Data
              PC
                           x=5              5      x
              r0       5
                           y=3              3      y
              r1       3
       ALU                 z=x+y            8      z
              r2       8   …                …
              r3           Instructions     Data
            fire_weapon();
     High-Level Languages (2/2)
52
     Source Program
                             Interpreter            Output
                Input
                         No target program exists
     Compilers vs. Interpreters (1/2)
57
Source
               Translator
Program
              Intermediate
                 Program      Virtual Machine   Output
                    Input
     Summary (1/2)
59