Before using Swarthmore's GitHub Enterprise, you'll need to complete the following configuration steps once:
SSH (Secure SHell) is a mechanism that allows you to interact with remote machines and issue commands to them. It typically uses a username and password, but in some cases (and this is one of them), you need something else: a cryptographic key.
If you already have an ssh key, you can skip this step. If you're not sure, you probably do not already have a key. You can check by issuing the command:
ls -l -a ~/.ssh
If you see files named id_rsa and id_rsa.pub, you already have a key. If those files aren't there, or you're told that you have no such directory named .ssh, you'll need to generate a key.
GitHub has a good comprehensive guide on the subject, but I'll give you the executive summary below:
Run the command ssh-keygen. This will give you the output:
$ ssh-keygen Generating public/private rsa key pair. Enter file in which to save the key (/home/[username]/.ssh/id_rsa):
Press enter to confirm the default location of /home/[username]/.ssh/id_rsa. Next, it'll ask you for a passphrase:
Enter passphrase (empty for no passphrase): Enter same passphrase again:
Set a passphrase that you'll remember and then confirm it a second time. After confirming your passphrase, it'll print a key fingerprint and some strange abstract ASCII artwork that you can safely ignore.
Next, we need to let GitHub know about this key we just created. Head over to https://github.swarthmore.edu and log in using your typical Swarthmore account credentials (same account you use for email). It may ask for your name, email address, or other information. Fill that in.
When you're properly logged in, click the small gear icon at the top right of the page to get to your account settings. Choose SSH Keys from the menu on the left. Click the Add SSH key button, and two boxes will appear. Fill in the name with anything you like, this is just to help you remember where you generated the key. I would suggest a name like CS account.
After you've named your account, you need to copy in the entire contents of the id_rsa.pub file that you generated earlier. Make sure you use the file ending in .pub. You can dump the contents of the file by executing:
cat ~/.ssh/id_rsa.pub
Copy the entire output of that file, paste it into the Key box on GitHub, and click Add Key.
Before you starting using the git command on the command line, you need to give it a basic configuration. This will tell git who you are, making it easy for you and your partner to identify who committed code to your shared repository.
Replace the email and name strings with your email address and name. If you have not run these commands, then the very first git commit will fail and tell you to run them.
git config --global user.email "username@swarthmore.edu" git config --global user.name "Your Name" git config --global push.default simple
That's it for now. We'll come back to git again after we go over a few examples.
/ | -------------- / | \ bin home usr ... | --------------- / | \ ... you ... | ---------------------- / | \ ... cs31 ... | ------------------------- / \ labs weeklylab / / \ ... week01 week02 ... / Files you'll copy over
Let's start by creating this directory structure and copying over some files:
cd # cd with no argument switches to your home directory mkdir cs31 # create a 'cs31' directory cd cs31 mkdir labs weeklylab # create a 'weeklylab' directory cd weeklylab mkdir week01 # create a 'week01' directory cd week01 pwd # print the current directory name # Copy some example files cp ~kwebb/public/cs31/week01/* . ls Makefile README printtypes.c testprog.c testprog_nocoments.c
C is a compiled language. Compiling is a process that translates C language code text to a machine code 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 named a.out that you can run.
We'll use the gnu compiler, gcc, to translate C to an executable form:
gcc testprog.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 testprog testprog.c ./testprog
Along with the code you copied over, there's a Makefile. In this file are rules for compiling executables from the .c source files that are executed by typing in the make command. make is very convenient way to compile without having to type in a long gcc command every time, you just need to type make:
make # this will compile all files as specified by the all: rule
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)
The files testprog.c and printtypes.c have some examples of printf format strings for printing out values of different types. Use it as a reference for printing out values in the lab assignment. Below is just a little info about printf and C types.
Let's open testprog.c and look for examples the following things:
Now let's compile and run the program:
make ./testprog
C has many different types for storing integer values. These types differ by the number of bytes they use to store values, and by weather or not they store both positive and negative values.
1 byte: | 2 bytes: | 4 bytes: | 4 or 8 bytes: (depends on arch) |
8 bytes: | char | short | int | long | long long |
unsigned char | unsigned short | unsigned int | unsigned long | unsigned long long |
When you allocate a variable of a specific type, you get a storage location of the appropriate number of bytes associated with that variable name:
int x; // 4 bytes of storage space to store a signed integer value unsigned char ch; // 1 byte of storage space to store an unsigned integer value
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:
### 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 hexidecimal (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 (to print numeric values of int, short, and char args) %ld: long int %lld: long long int %u: unsigned %lu: long unsigned %llu: long long unsigned %p: an address value %f: float or double %lf: double %e: float or double in scientific notation %g: float in either %e or %f format %c: char (ex. 'x') %s: string (ex. "hello there") ### Specifying field width: %5d: print out the value in decimal in a field of with 5 %-5d: print out the value in decimal in a field of with 5, left justified %6.4f: print out a float in a field with of 6 with a precision of 4
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 and type and name of each parameter.
// sum: a function that computes the sum of two values // x, y: two int parameters (the values to add) // returns: an int value (the sum of its 2 parameter values) int foo(int x, int y) { int z; // a local variable declaration z = x + y; // an assignment statment return z; // return the value of the expression z } // a function that does not return a value has return type void void blah( ) { printf("this function is called just for its side effects\n"); } int main() { int p; // local variable declaration p = sum(7, 12); // call to function that returns an int value printf("%d\n", p); blah(); // call to void function return 0; }
Try adding a simple function to testprog.c, something like sum above, then make a call to in from the main function. Compile testprog.c and try running it to see what happens.
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 # print an expression in different representations: # (/t in binary, /x in hexidecimal, default is decimal): (gdb) print/t 1234 # print/t: print decimal value 1234 in binary format # p is shorthand for print (gdb) p/x 1234 # p/x: print value in hexidecimal format (gdb) p/d 1234 # p/d: print value in decimal format (the default) # 0x is the prefix for a hexidecimal 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 (gdb) p/t 0b101001001 + 0xa2 # add a binary and a hex value, print result in binary # you can re-cast a value as a specific C type: (gdb) p/t (char)(12) # tell gdb that the value 12 is a char (1 byte) and print as binary (gdb) p/t (char)(-12) # print -12 char value (1 byte) in binary