Lab 2 C Programming On Linux, Mac OS X Course: Operating Systems
Lab 2 C Programming On Linux, Mac OS X Course: Operating Systems
Lab 2
C Programming on Linux, Mac OS X
Course: Operating Systems
• Review basic shell commands and practice with vim on Linux, Mac OS X.
Content:
Result:
• After doing the lab, student can type a program without GUI on Linux/Mac OS
C by vim.
1
1 Introduction
1.1 Vim
Vim is the editor of choice for many developers and power users. It‘s a “modal” text
editor based on the vi editor written by Bill Joy in the 1970s for a version of UNIX. It
inherits the key bindings of vi, but also adds a great deal of functionality and extensibility
that are missing from the original vi.
Vim has two modes for users:
To turn the Insert mode to Command mode, we type ESC key or Crtl − C. Otherwise,
to enter the Insert mode, type i or I, a, A, o, O. Some of basic commands in V im:
• Save: enter :w
• Undo: enter u
Furthermore, V im has a mode called “visual” that allows user to chose a paragraph for
copying or, moving. To enter this mode, we need to turn the editor into Command
mode and press “v”. After that, user use “arrow” keys to chose the paragraph, and then
use the following commands:
• Copy: enter y
• Cut: enter d
• Paste: enter p
2
1.2 C programming on Linux/Mac OS X
GNU C Coding Standards
• Put a comment on each function saying what the function does, what sorts of
arguments it gets, and what the possible values of arguments mean and are used
for.
• Please explicitly declare the types of all objects. For example, you should explicitly
declare all arguments to functions, and you should declare functions to return int
rather than omitting the int.
source
code executable
(.c, .cc, .h) binaries
Preprocessor Compiler Assembler Linker
• Preprocessor: takes the source code, the preprocessor directives and then expand
the source code.
• Assembler: converts the assembly code into object code by using an assembler
• Linker: combines the object code of library files with the object code of our pro-
gram.
3
Compilers and Libraries: Apple provides a customized/optimized GNU CC, with
backends for C, C++, Objective-C and Objective-C++. Compilers for many other lan-
guages are available either precompiled (such as the XL Fortran Advanced Compiler from
IBM), or can be compiled from source, which is not any harder in general than compiling
the same source on, say, Linux or FreeBSD. The LLVM compiler is the next-generation
compiler, introduced in Mac OS X. In Xcode of Mac OS X, the LLVM compiler uses the
Clang front end to parse source code and turn it into an interim format.
4
2 Practice
2.1 Compile and run a program
Steps for creating a program
We can compile the program directly from the source code file without the step of
creating object file. However, this way can cause the difficulty when identifying
errors.
5
hello hello . c hello . o
# To e x e c u t e t h e b i n a r y f i l e
$ ./ hello
• During compiling a program, the source code can make some errors. The compiler
provides debuggers that show the information of errors. The structure of showing
errors: <file>:<row>:<column_letter>:<type>:<detail>
2.2 Makefile
A makefile is a file containing a set of directives used with the make build automation
tool. Most often, the makefile directs make on how to compile and link a program. Using
C/C++ as an example, when a C/C++ source file is changed, it must be recompiled.
If a header file has changed, each C/C++ source file that includes the header file must
be recompiled to be safe. Each compilation produces an object file corresponding to the
source file. Finally, if any source file has been recompiled, all the object files, whether
newly made or saved from previous compilations, must be linked together to produce
the new executable program.[1] These instructions with their dependencies are specified
in a makefile. If none of the files that are prerequisites have been changed since the last
time the program was compiled, no actions take place. For large software projects, using
Makefiles can substantially reduce build times if only a few source files have changed. A
makefile consists of “rules” in the following form:
# comment
# ( n o t e : t h e <tab > i n t h e command l i n e
# i s n e c e s s a r y f o r make t o work )
t a r g e t : dependency1 dependency2 . . .
<tab> command
6
Where,
• target: a target is usually the name of a file that is generated by a program;
examples of targets are executable or object files. A target can also be the name
of an action to carry out, such as "clean".
int main ( ) {
helloworld ( ) ;
return 0 ;
}
// F i l e : h e l l o . h
void h e l l o w o r l d ( void ) ;
// F i l e : h e l l o . c
#include " h e l l o . h"
#include <s t d i o . h>
void h e l l o w o r l d ( void ) {
p r i n t f ( " H e l l o , ␣ world \n" ) ;
}
In this example, we compile .c files into object files .o, and then link all of object files
into a single binary. Firstly, that is the process of compiling source code files into object
files.
• main.o: main function in main.c calls helloworld() which is declared in hello.h.
Thereby, to compile main.c, we need the information declared from hello.h. To
create main.o, we need hello.h and main.c. Therefore, the rule for creating main.o
is:
main . o : main . c h e l l o . h
g c c −c main . c
7
• hello.o: similar to the rule of main.o, we need two files named hello.c and hello.h
to create hello.o. Note that hello.c using printf() in the library stdio.h to print the
output on screen. However, this is the library integrated with GCC, so we do not
need to fill in the dependency of the rule.
hello . o : hello . c hello .h
g c c −c h e l l o . o
• hello: Because helloworld is declared in hello.h, but it is defined in hello.c and com-
piled into the binary in hello.o, therefore, if the main function calls this function,
we need to link hello.o with main.o to create the final binary. This file depends on
hello.o and main.o.
a l l : main . o h e l l o . o
g c c main . o h e l l . o −o h e l l o
• Finally, we can add the rule of clean to remove all of object files and binaries in
case of compiling an entire program.
clean :
rm −f ∗ . o h e l l o
main . o : main . c h e l l o . h
g c c −c main . c
clean :
rm −f ∗ . o h e l l o
With this Makefile, to re-compile the whole program, we call:
$ make a l l
To remove all of object files and binaries, we call
$ make c l e a n
If we need to create an object file - main.o, we call
$ make main . o
If we only call “make”, the default rule of Makefile is executed - “make all”.
8
References
• C programming
– Brian Kernighan, and Dennis Ritchie, "The C Programming Language", Sec-
ond Edition
– Randal E. Bryant and David R. O’Hallaron, "Computer systems: A Program-
mer‘s Perspective", Second Edition
• Makefile:
– A simple Makefile tutorial http://www.cs.colby.edu/maxwell/courses/
tutorials/maketutor/
– GNU Make Manual https://www.gnu.org/software/make/manual/make.
html
9
3 Exercises
3.1 Questions
1. What are the advantages of Makefile? Give examples?
2. Is there any other automatic compilation tool besides Makefile? Give some names?
What are the reasons for creating new compilation tools?
3. In case of source code files located in different places, how can we write a Makefile?
#endif
// r e a d l i n e . h
#i f n d e f READ_LINE_H
#define READ_LINE_H
int r e a d _ l i n e ( char ∗ s t r ) ;
#endif
1. Write factorial.c to implement function factorial(): the function get an integer and
return an array of char containing digits of the result. For example factorial(10) returns
char[10]={3 6 2 8 8 0 0}
2. Write readline.c to implement read_line(): read_line() gets data from stdin (key-
board), line-by-line. The content from stdin will be recorded on the parameter of this
function named str. The result of read_line() indicates that whether the line is an
integer or not. For example, with the input string below:
H e l l o , world
O p er a t i n g system
Computer S c i e n c e and E n g i n e e r i n g
123
10
After calling the function, read_line() writes “Hello,world” into str and returns 0. The
second calling will write “Operating system” into str and return 0. The third calling will
write “Computer Science and Engineering” into str and return 0. The last call will write
“123” into str and return 1.
3. Write main.c to create an executable file named myfactorial that reads input from
stdin line by line and compute factorial if the line is an integer (each line does not exceed
50 letters). Then print factorial if the line is an integer else print -1. Write a Makefile
to compile the program at least two targets:
// main . c
#include <s t d i o . h>
#include " r e a d l i n e . h"
#include " f a c t o r i a l . h"
#endif
Note: As these exercises are graded automatically, thereby, student need to implement
the program by the requirements mentioned above. Student compress all of files .txt (
answers of $3.1 ), .c, .h, Makefile in a zip file named: lab2-<studentID>.zip.
11
Makefile example
1 FC=g f o r t r a n
2 CC=g c c
3 CP=cp
4
5 .PHONY: a l l c l e a n
6
7 OBJS = mylib . o mylib_c . o
8
9 # Compiler f l a g s
10 FFLAGS = −g −t r a c e b a c k −heap−a r r a y s 10 \
11 −I . −L/ u s r / l i b 6 4 −lGL −lGLU −lX11 −l X e x t
12
13 CFLAGS = −g −t r a c e b a c k −heap−a r r a y s 10 \
14 −I . −lGL −lGLU −lX11 −l X e x t
15
16 MAKEFLAGS = −W −w
17
18 PRJ_BINS=h e l l o
19 PRJ_OBJS = $ ( a d d s u f f i x . o , $ (PRJ_BINS ) )
20
21 o b j e c t s := $ (PRJ_OBJS) $ (OBJS)
22
23 a l l : myapp
24
25 %.o : %. f 9 0
26 $ (FC) −D_MACHTYPE_LINUX $< −c −o $@
27
28 %.o : %.F
29 $ (FC) −D_MACHTYPE_LINUX $< −c −o $@
30
31 %.o : %. c
32 $ (CC) −D_MACHTYPE_LINUX $< −c −o $@
33
34 myapp : o b j e c t s
35 $ (CC) $ (CFLAGS) $^ $ ( o b j e c t s ) −o $@
36
37 clean :
38 @echo " C l e a n i n g ␣up . . "
39 rm −f ∗ . o
40 rm −f $ (PRJ_BINS)
12
Revision History
13