Introduction to C, Linux/Unix, Makefile, CSE Servers
In this programming assignment you will be introduced to
Before you embark on writing some code here are some places to begin learning about these topics. This will serve as a good reference to use when you need help or get stuck.
There are lots of resources online to learn C. C and C++ are very similar, and C++ is a superset of C. You can use either C or C++ for any programming assignments. Here are a few resources for C:
There are two main methods for accessing Linux/Unix OS functions: System V and Posix. System V was developed in 1983 at AT&T and many descendants of that system are still based on it. It’s competition was primarily the BSD variants of Unix with a competing standard for the underlying API. However, in 1988 the IEEE Computer Society decided to standardize this creating the Portable Operating System Interface (POSIX) standard for maintaining compatibility between Unix variants.
Most operating systems are now either POSIX compliant, or mostly POSIX compliant. This includes Mac, Windows, Android, VxWorks, iOS, and most distributions of Linux. In this class I strongly suggest you use the POSIX API as it will make your code interoperable between OSs. I also think many of the POSIX functions are easier to use.
Here is a list of POSIX C library functions. These are also available as man pages in your shell.
man
(or manual) pages are key to your programming assignments. man
pages can be accessed within a *nix shell via the command man <topic>
. Many topics relating the Unix kernel, C programming, and even some abstract topics are available. A pretty good list exists here or here.
make
is a tool to build a software project. It uses a file called Makefile
or makefile
to do this. You will use make
in this class to build your software projects. You will need to build your own Makefile
for some programming assignments, while in others it will be given. Either way you should have an idea of how to write a Makefile
, how to use it, and do basic debugging on it. Some good resources are here:
One way to make your life significantly easier in future programming assignments if you plan to develop on your own machine is to setup Makefile targets that can automatically:
There are numerous ways to get your code onto the CSE servers and compile and execute your code. Check out the UNL CSE FAQ for options.
Perhaps the easiest is to:
scp
to “secure copy” your code to your home directory.
scp <files> <CSEusername>@cse.unl.edu:<directory path on CSE server>
ssh
to login to the CSE servers
ssh <CSEusername>@cse.unl.edu
If you tire of writing your password every time you login to the CSE servers you can setup a private/public key pair. Instructions for doing that can be found by googling “ssh key setup” or similar. If you do this make sure you never share, show, or divulge in any way your private key. You put the public key on the server, and the private key remains on your laptop.
In these exercises we will develop versions of some of the Unix tools (cat, echo) and use the program to introduce the POSIX API’s and Unix concepts. But let’s start with doing a review of C or C++.
Please review usage of pointers in C, dynamic memory allocation (malloc
and free
). Just google “pointers in C” to get lots of great hits. If you’re keen on C++, you can use Google to get many tutorials on using objects in C++.
The primary difference between C and C++ is the use of objects in C++. C has no concept of “objects” and therefore everything is procedural. I don’t perceive that one is easier than the other in this course. The only slight advantage C++ may have is it’s native handling of strings.
For this exercise write a program in C/C++ that prints “Hello World” to the terminal. Use a Makefile you wrote to compile it. If you’re not working on the CSE servers, upload it to the CSE servers and compile it and run it there to ensure you can test your code there.
Feel free to utilize the code we looked at in class and which is in the directory for this programming assignment.
In this exercise write a C/C++ program that will echo back to the terminal the input given to the program. You can learn more about echo
by typing man echo
into a terminal. This exercise will help you learn to work with command line arguments. Remember the function prototype for C/C++ is
int main(int argc, char* argv[]);
or int main(int argc, char** argv);
where argc
is the number of arguments and argv
is a pointer to an array of pointers (remember C has no notion of strings). Each member of the array points to the characters in each argument to the program. A representation of this can be seen here
argv
representationYou can read more about it by googling “argc and argv in C.” At this point you just need to parse the arguments and print them back to the terminal. A for
loop should do the job nicely.
Here you will write a C/C++ program that will concatenate and print the contents of the files presented as command line arguments. Read the man page on cat
to learn more. This will help familiarize you with opening, closing, and reading files.
The steps to do this exercise are:
There are roughly two main strategies for doing File I/O here.
stdio.h
. These are C functions that utilize the underlying system libraries. As such they’re perhaps a little cleaner and easier to use.Typically, the C library functions look like fopen
, fclose
, etc. and work with “streams” represented by FILE
. The POSIX system functions look like open
, close
, etc. and work with a file descriptor (which is really just an int
). These types are nearly identical and can be converted to the other easily.
Feel free to use either one you want, but it is generally recognized that working with “streams” is easier.
Finally, you should go through the process of uploading and testing your code on the CSE servers. Pick one exercise from above and upload your code, any Makefiles, and any test cases to the CSE servers. Then login to the CSE servers and build and test the code you uploaded to ensure it performs the same as on your machine.
If your code doesn’t compile, or doesn’t work the same on the CSE servers you need to figure out why since we will grade everything on the CSE servers. If you can’t figure out why, you might need to do all your development directly on the CSE servers.
There are a couple important Unix concepts worth understanding in preparation for our programming assignments. In the man pages, some of them use the term “stream,” to discuss I/O while others use “descriptor.” Read this for an explanation.
This also brings us to another important concept. One of the core philosophies in Unix, is that everything is a file (or treated like a file to be more specific). Files, directories, devices (e.g., terminal, storage, processor) are all treated as files. What this ties back to is that, we can open, read and write to the devices, console, directory etc. the same way as a file. Given this abstraction, it is often easier to visualize the data as just a stream of bytes. This article talks more about it.
This concept extends to the default inputs and outputs. Whenever Unix creates a process, it opens three files (or streams) by default.
STDIN_FILENO
= 0)STDOUT_FILENO
= 1)STDERR_FILENO
= 2)These streams are handles to default input and output. stdout and stderr are usually mapped to the terminal (or console). This is the reason any print statement appears on the terminal. One of the nice parts about treating things as “streams” is that we don’t need to worry about where the data is going. So if, for example, we decide that we don’t want the output to appear on the terminal, we can remap the output descriptor to a file instead. Similarly we could read from a file instead of terminal by remapping stdin to something else.
From the perspective of the process, it just needs to know the descriptor it should read and write to. The pipe command |
, and the file redirector commands >
, <
work in this way. You should get used to using those on the command line, and understand how they work.