Goals for this week:

  1. Setting up directory structure for CS31 course work.

  2. Set up our Swarthmore GitHub accounts.

  3. Practice compiling and running C programs: gcc and using make.

  4. Using GDB as a binary calculator.

  5. Introduction to Lab 1 and C syntax.

1. Lab Directories

Each week you will copy over some example code that we will talk through and practice in lab. These examples are related to the assigned lab, so remember to refer back to them, and back to the appropriate webpage, as these can be helpful resources when working on lab assignments.

Start by creating a WeeklyLabs subdirectory in your cs31 directory. In this directory you will create subdirectories for each week, into which you will copy files that we will work on in lab. This week you will create a week01 subdirectory. Your directory structure for cs31 will look something like this:

              /
              |
          ------------
         /    |       \
     ...    home      ...
              |
          -------------
         /    |        \
     ...     you        ...
              |
        ------------------
       /      |           \
    ...     cs31           ...
              |
         -------------------
        /                   \
     labs                   WeeklyLabs
      /                   /       \
   ...               week01      ...
                       /
               Files you will copy over

Let’s start by creating this directory structure and copying over some files.

Follow along with me these steps.

Do not type the $, that is the shell prompt. Anything after a # symbol is a comment about the command.
$ cd                       # cd with no argument switches to your home directory (/home/you/)
$ mkdir cs31               # create a directory named 'cs31'
$ cd cs31                  # cd into cs31 (change current working directory to cs31)
$ pwd                      # print the current directory name
/home/you/cs31             # the shell will respond with your current location
$ mkdir labs               # create a 'labs' directory
$ mkdir WeeklyLabs         # create a `WeeklyLabs` directory
$ cd WeeklyLabs
$ pwd
/home/you/cs31/WeeklyLabs  # the shell will respond with your current location
$ mkdir week01             # create a 'week01' directory
$ cd week01
$ pwd
/home/you/cs31/WeeklyLabs/week01

# USAGE: cp <source> <destination>
$ cp ~newhall/public/cs31/week01/*  ./      # ./ means "here" (current directory)
$ ls
Makefile  README  firstprog.c  firstprog_nocomments.c   printtypes.c

Here are a couple helpful using unix resources:

2. Unix resources and editing files

For Lab 1 you will need to use Vim, and you should remind yourself or learn some of basic Unix commands for using our system. The Lab 0 page has more information about unix and running vimtutor lessons to learn Vim. And there are links to other resources listed in Section 7.

3. C Programming

We are going to do just a little bit of C programming in this week’s lab. Next week you will learn much more, and write a larger C program.

3.1. Compiling and running C programs

C is a compiled language. Compilation is a process that translates C program code in a C source file into a binary machine-code form of the program that the system knows how to execute (the computer doesn’t understand high-level languages like C or Python or Java, instead it understands low-level machine code). If compilation succeeds (there are no syntax errors in your code), the compiler creates an executable file (the deafult name of which is a.out) that you can run from the comand line. For more info, refer to the basics of compiling and running C programs (or to chapt 1.1.1 for a more verbose version).

We’ll use the gnu compiler, gcc, to translate C to an executable form:

$ gcc firstprog.c

Then enter the path name of executable file on the command line to run it:

$ ./a.out

gcc supports command line options to include debug information in the executable file (-g) and to specify the name of the executable file (-o filename) rather than use the default "a.out". Let’s try it out on one of the files you copied over:

$ gcc -g -o firstprog firstprog.c
$ ./firstprog

Along with the code you copied over, there’s a Makefile. The Makefile contains rules for compiling executables from the .c source files. To execute these rules, type make command:

$ make        # this will compile all files as specified by the all: rule

make is a convenient way to compile without having to type in a long gcc command every time.

To clean up all the files that were compiled by make, you can run make clean:

$ make clean  # this removes all files generated by make (the can be rebuilt)

3.2. First C program: main, variables, printf

Let’s open firstprog.c in vim. For example:

$ vim firstprog.c

Look for examples of:

  • C comments

  • How to import a C library (stdio.h)

  • The main function definition, function bodies ( { } ), and C statements (end in ;)

  • Defining and using constants

  • Declaring local variables (note that all are declared at the top of a function body)

  • printf function (similar to Python print function with print formatting)

  • Declaring, defining, and calling a function.

  • Note that all the code is inside the body of a function!

Now let’s compile and run the program:

$ make
$ ./firstprog
Tip

We suggest using at least two terminals when when working on code. In one you run vim and edit and save changes to the source code (.c) file. In the other terminal you compile and run your program.

Try Out

  • There are some suggestions for changing the code in a TODO comments. Let’s try adding one of them together. You can try some of the others on your own.

    When we change the code we need to save it in our editor, and then recompile the program before running it again:

    $ vim firstprog.c   # open C file in an editor to edit it, save changes
    $ make              # recompile
    $ ./firstprog       # run
    Save and Recompile

    If you have used Python you may be used to making changes in your editor, saving, and running it immediately. In C, there is one extra step between saving the file and running which is recompiling it. Every time you change your C program, you have to recompile it to build a new binary

3.2.1. printf formatted output

printf uses placeholders for specifying how a value should be printed (how its series of bytes be interpreted). See printtypes.c for examples. Here is a brief summary (note: you won’t need to use all of these in the lab assignment):

### Specifying the numeric representation:

   %d: print out value in decimal  (base 10)
   %u: print out value in unsigned decimal  (base 10)
   %x: print out value in hexadecimal  (base 16)
   %o: print out value in octal (base 8)
   (there is no formatting option to display the value in binary)

### Specifying the type

   %d:   int, short, char (print numeric value of char arg, ex. 88)
   %u:   unsigned int, unsigned short, and unsigned char

   %ld:  long int
   %lu:  long unsigned

   %lld: long long int
   %llu: long long unsigned

   %c:   char (print character value of char arg, ex. 'X')
   %s:   string  (ex.  "hello there")
   %f:   float or double
   %lf:  double
   %e:   float or double in scientific notation
   %g:   float in either %e or %f format
   %p:   an address value

3.2.2. C functions (quick overview)

The syntax for functions in C is similar to that in Python, except that C function definitions must define:

  • the return type of the function

  • the name of the function

  • the parameter list: the type and name of each parameter.

  • the function body:

    • local variable declarations

    • set of statements executed when the function is called.

Here are a couple different examples of functions (Note: We will learn more C including writing functions next week. This week you will use only void functions like blah):

/*
 * blah: prints out a message
 *   no parameters (void)
 *   no return value  (void)
 */
void blah(void) {
   printf("this function is called just for its side effects\n");
}

/*
 * sum: a function that computes the sum of two values
 *   x, y: the two values to add together (ints)
 *   returns: the sum of the two values (an int)
 */
int sum(int x, int y) {
   int z;      // a local variable declaration
   z = x + y;  // an assignment statement
   return z;   // return the value of the expression z
}

And here is an example of how each function could be called from main:

int main(void) {

   int p;             // local variable declaration

   blah();           // call a void function with no parameters

   p = sum(7, 12);   // call an int function with parameters

   printf("sum is %d\n", p);

   return 0;        // main returns an int value, 0 means success
}

Try Out

  • In firstprog.c add a new function like blah (you should name it something more meaningful), and call your function from main. Remember you need to add a new function prototype for your function.

4. GDB as a calculator

The GNU debugger, gdb, is the C debugger we will use in this class. Usually, we will use gdb to debug a program, but this week we are going to use gdb as calculator.

gdb’s print command can be used to print the value of a expression in different representations (binary, decimal, hex); you can use it as a simple calculator to verify answers to hex, binary, and decimal arithmetic. For this use of gdb, we don’t have to have an executable to run gdb on. We can just run gdb, and then call its print command:

$ gdb                   # start a gdb session

# print an expression in different representations:
# (/t in binary, /x  in hexadecimal, default is decimal):

(gdb) print/t 1234       # print/t: print decimal value 1234 in binary format
(gdb) p/t 1234           # p is shorthand for print
(gdb) p/x 1234           # p/x: print value in hexadecimal format
(gdb) p/d 1234           # p/d: print value in decimal format (the default)

# 0x is the prefix for a hexadecimal literals
# 0b is the prefix for a binary literals
# no prefix:  for decimal literals

(gdb) p 0xabf1           # print the hex value abf1 as decimal
(gdb) p 0b0101           # print the binary value 0101 as decimal
(gdb) p/t 0x1234         # print the hex value 0x1234 as binary
                         # (note: leading 0's are not printed out)
(gdb) p/d 0b1010         # print the binary value 01010 as decimal
(gdb) p/x  0b10100000    # print a binary value in hex

# add a binary and a hex value, print result in binary
(gdb) p/t 0b101001001 + 0xa2

# you can re-cast a value as a specific C type:

# tell gdb that the value 12 is a char (1 byte) and print as binary
(gdb) p/t (char)(12)
(gdb) p/t (char)(-12)   # print -12 char value (1 byte) in binary

(gdb) quit              # exit the gdb session

Try Out

Try some of these in gdb (let’s try one or two together):

  • print out the value 128 in binary.

  • print out the value 128 in hex.

  • print out the value -128 in binary.

  • print out the value -128 in hex.

  • print the result of adding -3 and 6 in binary.

  • print the result of adding -3 and 6 in hex.

  • print out the char value 113 in binary.

  • print out the char value 113 in hex.

  • print out the char value 113 in decimal.

5. One-time git/GitHub configuration

Before using Swarthmore’s GitHub Enterprise, you’ll need to complete some one time setup steps. Once you’ve done that, you should follow steps to clone your Lab1 repo using git: GitHub for lab checkout.

More details are on {lab00} assignment page. We will help you get this set up if you had difficulties.

6. Lab 1 Intro

Next, we’ll take a look at the Lab1 assignment. Note that all course assignments and lab practice (in-lab work, lab assignments, and homework assignments) will be posted to the Schedule part of the course webpage.

7. Handy Resources