The C Programming Language- Fast
- Good optimizing compilers
- Not too high-level (Java, Python, Lisp)
- Not too low-level (Assembly)
- Although appearing lower-level as the years go by
- Easy manipulation of bits, bytes, words, and pointers (addresses)
- Many C types map directly to registers
int x = 3, y = 7; x = x + y;
==>
// x86 assembly movl $3, %eax movl $7, %ebx addl %ebx, %eax
// ARM assembly mov r0, #3 mov r1, #7 add r0, r0, r1
- Explicit memory allocation
- Relatively portable (non-architecture specific code)
- Not as portable as Java bytecode running on a JVM
- Most OS kernels written in C with some assembly
- There are some new systems languages
C Basics- In C there are two main concepts
- File structure
- .c files hold functions and variable definitions
- .h files hold macros, function and variable declarations
- Comments
- /* comment here, can span multiple lines */
- // comment to end of line
- Blocks enclosed in braces {}
- Statements terminated with semicolon ;
- See helloloop.c:
helloloop.c#include <stdio.h>
int main(int argc, char *argv[])
{
int i;
for (i = 0; i < 3; i++) {
printf("Hello World %d\n", i);
}
return 0;
}
To compile:
$ gcc -o helloloop helloloop.c
To run:
$ ./helloloop
C Data Types- Native types
- char, unsigned char, int unsigned int, float, double
- arrays, enum
- pointers
- bool
- Programmer-defined types
- structs and unions
- typedef - an abbreviation
Different Architectures - 32bit vs 64bit
- Most laptops, desktops, and servers are 64bit today
- Mobile devices are often 32bit - although this is changing
- 32bit: 4 byte int, 4 byte long and pointer is 4 bytes
- 64bit: 4 byte int, 8 byte long and pointer is 8 bytes
- Processors - instructuion set architecture
- x86 family
- ARM family
- Others
- See sizes.c
sizes.c #include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char **argv)
{
printf("sizeof(char) = %lu\n", sizeof(char));
printf("sizeof(int) = %lu\n", sizeof(int));
printf("sizeof(long) = %lu\n", sizeof(long));
printf("sizeof(long long) = %lu\n", sizeof(long long));
printf("sizeof(float) = %lu\n", sizeof(float));
printf("sizeof(double) = %lu\n", sizeof(double));
printf("sizeof(int *) = %lu\n", sizeof(int *));
printf("sizeof(uint8_t) = %lu\n", sizeof(uint8_t));
printf("sizeof(size_t) = %lu\n", sizeof(size_t));
return 0;
}
C Operators- Bitwise operators (used for masking/accessing bits)
- Relational operators
- Use parentheses to force evaluation order
- if (~(a&b)) == c) { x = 1; }
Control Statements- if / else / else if
- for (x = 1; x < N; x++) { /* code */ }
- while (x > 1) { /* code */ }
- switch / case / default / break
- goto
C Functions- Parameters, arguments, local variables, return value
- Basic execution
- Caller sets arguments (in registers or on stack)
- call/jump to address of function
- Function body creates activation frame for local variables
- Function body sets return value (in register, e.g., eax or r0) the returns (return or update pc)
C Practice- All arguments to functions are passed by value
- Use pointers to "pass by reference"
- Technically no "pass by reference" in C
- Explicit memory allocation and deallocation with malloc() and free()
- Memory is a bit more complicated in the kernel
- Structs with pointers to build linked data structures
- Pointers to functions
- Macros for speed - less used with inline functions
- Global variables are not always bad
- Use bool for true/false
- New types with typedef (typically not used in kernel code)
The C Library- The Standard C Library (libc)
- Strings: strcpy(), strlen(), etc.
- I/O: printf()
- Math: sin(), cos(), pos(), etc.
- Others
- Man pages:
System Calls- File I/O
- open(), close(), read(), write()
- Man pages
Command Line Arguments- C and UNIX define a way to pass arguments to a program
- int main(int argc, char *argv[])
- argc is the number of args (including the command name itself)
- argv is an array of strings
- Really it is an array of pointers to strings
- See args.c:
args.c
/* args.c - demonstrate command-line processing */
#include <stdio.h> /* Standard C header file with prototypes and */
/* constants for basic input/output functions */
/* (e.g., printf) */
int main(int argc, char *argv[])
{
/* All variable declarations must go at the top of a function */
/* declaration, even variables for loops */
int i;
printf("argc = %d\n", argc);
for (i = 0; i < argc; i++) {
printf("argv[%d] = %s\n", i, argv[i]);
}
/* return exit code to shell */
return 0;
}
Exercise: sumargs- Write a C program that sums up all of the command line arguments and prints the results:
$ ./sumargs 1 2 3 4 5 15 - Hint use the C library function atoi() to convert string arguments to integers
Basic Output with printf- printf is a sophisticated function for generating output
- printf can output the values of C variables
- printf can format output
- See printf.c:
printf.c
/* printf.c - program to demonstrate printf output */
#include <stdio.h>
int main(int argc, char **argv)
{
char name[] = "Some string";
int i,j;
float fi;
double di;
int *ptr;
/* use %s to print a string, \n is a "newline" */
printf("Here is: %s\n", name);
/* usr %d to print integers */
/* just use multiple specifiers to print multiple variables */
i = 16;
j = 32768;
printf("i is %d and j is %d\n", i, j);
/* use %f to print a float */
fi = 22.0/7.0;
printf("fi is %f\n", fi);
/* use %lf to print a double */
/* also can specify the "format" */
di = 22.0/7.0;
printf("di is %2.20lf\n", di);
printf("fi is %2.20lf\n", fi);
/* use %X and %x to print in hexidecimal (good for pointers) */
ptr = &i;
printf("ptr is %X\n", ptr);
printf("ptr is %x\n", ptr);
/* use %c to print a single character */
printf("%c%c%c\n", 'a', 'b', 99);
/* stdout and stderr */
printf("Hello there printf\n");
fprintf(stdout, "Hello there fprintf\n");
fprintf(stderr, "Hello there stderr\n");
return 0;
}
Working with C Strings- In C, strings are an array of characters with a null termination character '\0' at the end.
- The length of a string does not include the null terminator
- The storage for a string must include space for the termination character
- Note: other languages work differently, e.g., Pascal includes length at beginning of string.
- Arrays and pointers can be used to access strings
- Be sure to know where the string is stored
- E.g., if you put it on the stack of a function, then return, the storage will be reused.
- See strings.c:
strings.c
/* strings.c - show how to use C strings */
#include <stdio.h> /* for printf, etc. */
#include <string.h> /* for str functions */
#include <stdlib.h> /* for malloc and free */
/* static memory allocation */
char *s1 = "This is string one";
char *s2 = "and this is string two";
char t1[256];
char t2[256];
int main(int argc, char *argv[])
{
char *p1;
/* basics */
printf("string s1 = %s\n", s1);
printf("length of string s1 = %d\n", strlen(s1));
/* copying */
strcpy(t1, s1); /* note: s1 must be null terminated */
printf("string t1 = %s\n", t1);
printf("length of string t1 = %d\n", strlen(t1));
/* concatenation */
strcpy(t2, s1);
strcat(t2, " "); /* add a space */
strcat(t2, s2);
printf("string t2 = %s\n", t2);
printf("length of string t2 = %d\n", strlen(t2));
/* comparison */
printf("is s1 equal to s1? strcmp = %d\n", strcmp(s1, s1));
printf("is s1 equal to t1? strcmp = %d\n", strcmp(s1, t1));
printf("is s1 equal to t2? strcmp = %d\n", strcmp(s1, t2));
/* see the "n" versions of the str functions */
/* dynamic memory allocation */
p1 = (char *) malloc(256);
strcpy(p1, t2);
printf("string p1 = %s\n", p1);
printf("length of string p1 = %d\n", strlen(p1));
free(p1);
return 0;
} System Calls for File I/O- File descriptor: a small non-negative integer that is a reference to an open file
- Use open() gain access to a file
- Use read(fd, buf, size) to read bytes from a file
- Use write(fd, buf, size) to write bytes to a file
filecopy.c #include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
int fd_in, fd_out;
int count;
char buf[1];
fd_in = open(argv[1], O_RDONLY);
if (fd_in < 0) {
printf("Cannot open %s\n", argv[1]);
exit(1);
}
fd_out = open(argv[2], O_CREAT | O_TRUNC | O_WRONLY, 0644);
if (fd_in < 0) {
printf("Cannot open %s\n", argv[2]);
exit(1);
}
while ((count = read(fd_in, buf, 1)) > 0) {
write(fd_out, buf, 1);
}
close(fd_in);
close(fd_out);
return 0;
}
Exercise: countlines- Write a C program that counts the number of lines in a file.
$ ./countlines foo 10
The C Preprocessor- Before compilation, C source files are preprocessed (e.g., translated)
- The C Preprocessor (cpp) handles:
- Include files: #include<foo.h>
- Macro expansion: #define NMAX 3
- Conditional compilation
- Most C programs use the preprocessor, especially OS kernels
Include Files- System include files (where are they?)
- Program local include files
- General rule: do not define storage (variables) within an include file, only data types, function prototypes, and macros
- Add an include directory to the search path:
- gcc -o main main.c -I/home/benson/src
- Now you can use: #include <foo.h>
Preprocessor Macros- Simple
- Parameterized
- Complex:
#define insert(e, l) do { \ e->next = l->head; \
l->head = e; \ } while(0)
Conditional Compilation- Used for portability and testing
#ifdef __LINUX___ printf("Linux\n");
#else printf("Unknown\n");
#endif /* __LINUX__ */
Include File Management- Conditional compilation can be used to make sure only one instance of an include file is preprocessed
#ifndef _FOO_H_ #define _FOO_H_
... include file contents ...
#endif /* _FOO_H_ */
C Pointers- Declare a pointer variable with "*" in type declarations:
- int *p;
- char *str;
- double *dp;
- struct foo *foo_ptr;
- Dereference a pointer with "*" in expressions:
- Use address of "&" to get the address of a variable:
- Use arrow "->" operator to access struct members through a pointer:
- foo.x = 1;
- foo_ptr->x = 1;
- (*foo_ptr).x = 1; /* same as above */
- All pointers are the same size:
- 32 bits (4 bytes)
- 64 bits (8 bytes)
- See pointers.c
pointers.c/* pointers.c - pointer usage examples */
#include <stdio.h>
int x;
int main(int argc, char *argv[]) {
int y;
int *p1;
int *p2;
x = 1;
y = 2;
printf("x = %d, y = %d\n", x, y);
p1 = &x;
p2 = &y;
(*p1) = 101;
(*p2) = 102;
printf("x = %d, y = %d\n", x, y);
printf("p1 = %p, p2 = %p\n", p1, p2);
return 0;
} |