0% found this document useful (0 votes)
26 views51 pages

Synapseindia Dotnet Development-Programming Language

The C programming language was designed in the early 1970s and influenced by other languages. It is traditionally used for systems programming but is also used for other applications. The C standard was established in 1989 and updated in later years. A C program includes source code files, header files that declare interfaces, a compiler to convert to object code, and a linker. It must have a main function as the entry point. Pointers in C reference memory locations and allow manipulation of data.

Uploaded by

tarunsingh19866
Copyright
© © All Rights Reserved
Available Formats
Download as PPT, PDF, TXT or read online on Scribd
Download as ppt, pdf, or txt
0% found this document useful (0 votes)
26 views51 pages

Synapseindia Dotnet Development-Programming Language

The C programming language was designed in the early 1970s and influenced by other languages. It is traditionally used for systems programming but is also used for other applications. The C standard was established in 1989 and updated in later years. A C program includes source code files, header files that declare interfaces, a compiler to convert to object code, and a linker. It must have a main function as the entry point. Pointers in C reference memory locations and allow manipulation of data.

Uploaded by

tarunsingh19866
Copyright
© © All Rights Reserved
Available Formats
Download as PPT, PDF, TXT or read online on Scribd
Download as ppt, pdf, or txt
Download as ppt, pdf, or txt
You are on page 1/ 51

Brief Introduction to the C

Programming Language

Introduction

The C programming language was designed by


Dennis Ritchie at Bell Laboratories in the early
1970s
Influenced by

ALGOL 60 (1960),
CPL (Cambridge, 1963),
BCPL (Martin Richard, 1967),
B (Ken Thompson, 1970)

Traditionally used for systems programming,


though this may be changing in favor of C++
Traditional C:

The C Programming Language, by Brian Kernighan


and Dennis Ritchie, 2nd Edition, Prentice Hall

Standard C

Standardized in 1989 by ANSI (American National


Standards Institute) known as ANSI C
International standard (ISO) in 1990 which was
adopted by ANSI and is known as C89
As part of the normal evolution process the standard
was updated in 1995 (C95) and 1999 (C99)
C++ and C

C++ extends C to include support for Object Oriented


Programming and other features that facilitate large
software development projects
C is not strictly a subset of C++, but it is possible to
write Clean C that conforms to both the C++ and C
standards.

Elements of a C Program

A C development environment includes


System libraries and headers: a set of standard libraries and
their header files. For example see /usr/include and
glibc.
Application Source: application source and header files
Compiler: converts source to object code for a specific
platform
Linker: resolves external references and produces the
executable module

User program structure

there must be one main function where execution begins


when the program is run. This function is called main
int main (void) { ... },
int main (int argc, char *argv[]) { ... }

A Simple C Program

Create example file: try.c


Compile using gcc:
gcc o try try.c

The standard C library libc is included


automatically
Execute program
./try
Note, I always specify an absolute path
Normal termination:
void exit(int status);

calls functions registered with atexit()

flush output streams


close all open streams
return status value and control to host
environment

/* you generally want to


* include stdio.h and
* stdlib.h
* */
#include <stdio.h>
#include <stdlib.h>
int main (void)
{
printf(Hello World\n);
exit(0);
}

Source and Header files

Just as in C++, place related code within the same


module (i.e. file).
Header files (*.h) export interface definitions

Do not place source code (i.e. definitions) in the header


file with a few exceptions.

function prototypes, data types, macros, inline functions and


other common declarations

inlined code
class definitions
const definitions

C preprocessor (cpp) is used to insert common


definitions into source files
There are other cool things you can do with the

Another Example C Program


/usr/include/stdio.h
/* comments */
#ifndef _STDIO_H
#define _STDIO_H
... definitions and protoypes
#endif

/usr/include/stdlib.h
/* prevents including file
* contents multiple
* times */
#ifndef _STDLIB_H
#define _STDLIB_H
... definitions and protoypes
#endif

#include directs the preprocessor


to include the contents of the file
at this point in the source file.
#define directs preprocessor to
define macros.
example.c
/* this is a C-style comment
* You generally want to palce
* all file includes at start of file
* */
#include <stdio.h>
#include <stdlib.h>
int
main (int argc, char **argv)
{
// this is a C++-style comment
// printf prototype in stdio.h
printf(Hello, Prog name = %s\n,
argv[0]);
exit(0);
}

Passing Command Line Arguments

When you execute a program you


can include arguments on the
command line.
The run time environment will
create an argument vector.

./try g 2 fred

argc = 4,
argv = <address0>

argv is the argument vector


argc is the number of arguments

Argument vector is an array of


pointers to strings.
a string is an array of characters
terminated by a binary 0 (NULL or
\0).
argv[0] is always the program name,
so argc is at least 1.

try\0
[0]
[1]
[2]
[3]
[4]

argv:
<addres1>
<addres2>
<addres3>
<addres4>
NULL

-g\0
2\0

fred\0

C Standard Header Files you may want to use

Standard Headers you should know about:


stdio.h file and console (also a file) IO: perror,
printf, open, close, read, write, scanf,
etc.
stdlib.h - common utility functions: malloc,
calloc, strtol, atoi, etc
string.h - string and byte manipulation: strlen,
strcpy, strcat, memcpy, memset, etc.
ctype.h character types: isalnum, isprint,
isupport, tolower, etc.
errno.h defines errno used for reporting system
errors
math.h math functions: ceil, exp, floor,
sqrt, etc.

The Preprocessor

The C preprocessor permits you to define simple


macros that are evaluated and expanded prior to
compilation.

Commands begin with a #. Abbreviated list:


#define : defines a macro
#undef : removes a macro definition
#include : insert text from file
#if : conditional based on value of expression
#ifdef : conditional based on whether macro defined
#ifndef : conditional based on whether macro is not
defined
#else : alternative
#elif : conditional alternative

Preprocessor: Macros

Using macros as functions, exercise caution:

flawed example: #define mymult(a,b) a*b

better: #define mymult(a,b) (a)*(b)

Source: k = mymult(i-1, j+5);


Post preprocessing: k = (i 1)*(j + 5);

Be careful of side effects, for example what if we did


the following

Macro: #define mysq(a) (a)*(a)


flawed usage:

Source: k = mymult(i-1, j+5);


Post preprocessing: k = i 1 * j + 5;

Source: k = mysq(i++)
Post preprocessing: k = (i++)*(i++)

Alternative is to use inlineed functions

Preprocessor: Conditional Compilation


Its generally better to use inlineed functions
Typically you will use the preprocessor to define
constants, perform conditional code inclusion,
include header files or to create shortcuts
#define DEFAULT_SAMPLES 100
#ifdef __linux

static inline int64_t


gettime(void) {...}

#elif defined(sun)
static inline int64_t
gettime(void) {return
(int64_t)gethrtime()}

#else

Another Simple C Program


int main (int argc, char **argv) {
int i;
printf(There are %d arguments\n,
argc);
for (i = 0; i < argc; i++)
printf(Arg %d = %s\n, i,
argv[i]);
Notice that the syntax is similar to Java
return
0;the above simple program?
Whats
new in

of course you will have to learn the new interfaces and utility
functions defined by the C standard and UNIX
Pointers will give you the most trouble

Arrays and Pointers

A variable declared as an array represents a contiguous


region of memory in which the array elements are
stored.
little endian byte ordering
0

int x[5]; // an array of 5 4-byte ints.


0
1
2

All arrays begin with an index of 0

3
4

memory layout for array x

An array identifier is equivalent to a pointer that


references the first element of the array
int x[5], *ptr;
ptr = &x[0] is equivalent to ptr = x;

Pointer arithmetic and arrays:

Pointers

For any type T, you may form a pointer type to T.

Pointers may reference a function or an object.


The value of a pointer is the address of the corresponding object or function
Examples: int *i; char *x; int (*myfunc)();

Pointer operators: * dereferences a pointer, & creates a pointer (reference to)


int i = 3; int *j = &i;
*j = 4; printf(i = %d\n, i); // prints i = 4
int myfunc (int arg);
int (*fptr)(int) = myfunc;
i = fptr(4); // same as calling myfunc(4);

Generic pointers:

Traditional C used (char *)


Standard C uses (void *) these can not be dereferenced or used in pointer
arithmetic. So they help to reduce programming errors

Null pointers: use NULL or 0. It is a good idea to always initialize pointers to


NULL.

Pointers in C (and C++)


Step 1:
int main (int argc, argv) {
int x = 4;
int *y = &x;
int *z[4] = {NULL, NULL, NULL, NULL};
int a[4] = {1, 2, 3, 4};
...

Note: The compiler converts z[1] or *(z+1) to


Value at address (Address of z + sizeof(int));
In C you would write the byte address as:
(char *)z + sizeof(int);
or letting the compiler do the work for you
(int *)z + 1;

Program Memory Address

x
y

z[3]
z[2]
z[1]
z[0]
a[3]
a[2]
a[1]
a[0]

4
0x3dc
NA
NA
0
0
0
0
4
3
2
1

0x3dc
0x3d8
0x3d4
0x3d0
0x3cc
0x3c8
0x3c4
0x3c0
0x3bc
0x3b8
0x3b4
0x3b0

Pointers Continued
Step 1:
int main (int argc, argv) {
int x = 4;
int *y = &x;
int *z[4] = {NULL, NULL, NULL, NULL};
int a[4] = {1, 2, 3, 4};
Step 2: Assign addresses to array Z
z[0] = a;
// same as &a[0];
z[1] = a + 1;
// same as &a[1];
z[2] = a + 2; // same as &a[2];
z[3] = a + 3; // same as &a[3];

Program Memory Address

x
y

z[3]
z[2]
z[1]
z[0]
a[3]
a[2]
a[1]
a[0]

4
0x3dc
NA
NA
0x3bc
0x3b8
0x3b4
0x3b0
4
3
2
1

0x3dc
0x3d8
0x3d4
0x3d0
0x3cc
0x3c8
0x3c4
0x3c0
0x3bc
0x3b8
0x3b4
0x3b0

Pointers Continued
Step 1:
int main (int argc, argv) {
int x = 4;
int *y = &x;
int *z[4] = {NULL, NULL, NULL, NULL};
int a[4] = {1, 2, 3, 4};
Step 2:
z[0] = a;
z[1] = a + 1;
z[2] = a + 2;
z[3] = a + 3;
Step 3: No change in zs values
z[0] = (int *)((char *)a);
z[1] = (int *)((char *)a
+ sizeof(int));
z[2] = (int *)((char *)a
+ 2 * sizeof(int));
z[3] = (int *)((char *)a
+ 3 * sizeof(int));

Program Memory Address

x
y

z[3]
z[2]
z[1]
z[0]
a[3]
a[2]
a[1]
a[0]

4
0x3dc
NA
NA
0x3bc
0x3b8
0x3b4
0x3b0
4
3
2
1

0x3dc
0x3d8
0x3d4
0x3d0
0x3cc
0x3c8
0x3c4
0x3c0
0x3bc
0x3b8
0x3b4
0x3b0

Getting Fancy with Macros


#define QNODE(type)
struct {
struct type *next;
struct type **prev;
}

\
\
\
\

#define QNODE_INIT(node, field)


do {
(node)->field.next = (node);
(node)->field.prev =
&(node)->field.next;
} while ( /* */ 0 );

\
\
\
\
\

#define QFIRST(head, field) \


((head)->field.next)
#define QNEXT(node, field) \
((node)->field.next)
#define QEMPTY(head, field) \
((head)->field.next == (head))
#define QFOREACH(head, var, field) \
for ((var) = (head)->field.next; \
(var) != (head);
\
(var) = (var)->field.next)

#define QINSERT_BEFORE(loc, node, field) \


do {
\
*(loc)->field.prev = (node);
\
(node)->field.prev =
\
(loc)->field.prev; \
(loc)->field.prev =
\
&((node)->field.next);
\
(node)->field.next = (loc);
\
} while (/* */0)
#define QINSERT_AFTER(loc, node, field) \
do {
\
((loc)->field.next)->field.prev =
\
&(node)>field.next;
\
(node)->field.next = (loc)->field.next; \
(loc)->field.next = (node);
\
(node)->field.prev = &(loc)>field.next;
\
} while ( /* */ 0)
#define QREMOVE(node,
field)
\
do {
\
*((node)->field.prev) = (node)>field.next;
\
((node)->field.next)->field.prev
=
\
(node)>field.prev;

After Preprocessing and Compiling


typedef struct wth_t
{
int state;
QNODE(wth_t) alist;
} wth_t;
#define QNODE_INIT(node,
do {
#define
QNODE(type)
\
(node)->field.next
struct
{
\=
(node)->field.prev
struct
type *next; \=
}struct
while type
( /* **prev;
*/ 0 ); \
}head: instance of wth_t
0x100 0
0x104 0x00100
0x108 0x00104

typedef struct wth_t {


int state;
struct {
CPP
struct wth_t *next;
struct wth_t **prev;
} alist;
} wth_t; \
field)
\
(node);
\
&(node)->field.next;\
memory layout after GCC

3 words in memory
QNODE_INIT(head, alist) <integer> state
<address> next
<address> prev

QNODE Manipulations
before
head
0x100 0
0x104 0x100
0x108 0x104

node0
0x1a0 0
0x1a4 0x1a0
0x1a8 0x1a4

#define QINSERT_BEFORE(head, node, alist)\


do {
\
*(head)->alist.prev = (node);
\
(node)->alist.prev = (head)->alist.prev;
\
(head)->alist.prev = &(node)->alist.next;\
(node)->alist.next = (head);
\
} while (/* */0)

QINSERT_BEFORE(head, node0, alist);

QNODE Manipulations
before
head
0x100 0
0x104 0x100
0x108 0x104

node0
0x1a0 0
0x1a4 0x1a0
0x1a8 0x1a4

#define QINSERT_BEFORE(head, node, alist)\


do {
\
*(head)->alist.prev = (node);
\
(node)->alist.prev = (head)->alist.prev;
\
(head)->alist.prev = &(node)->alist.next;\
(node)->alist.next = (head);
\
} while (/* */0)

QINSERT_BEFORE(head, node0, alist);

head
0x100 0
0x104 0x1a0
0x108 0x104

node0
0x1a0 0
0x1a4 0x1a0
0x1a8 0x1a4

QNODE Manipulations
before
head
0x100 0
0x104 0x100
0x108 0x104

node0
0x1a0 0
0x1a4 0x1a0
0x1a8 0x1a4

#define QINSERT_BEFORE(head, node, alist)\


do {
\
*(head)->alist.prev = (node);
\
(node)->alist.prev = (head)->alist.prev;
\
(head)->alist.prev = &(node)->alist.next;\
(node)->alist.next = (head);
\
} while (/* */0)

QINSERT_BEFORE(head, node0, alist);

head
0x100 0
0x104 0x1a0
0x108 0x104

node0
0x1a0 0
0x1a4 0x1a0
0x1a8 0x104

QNODE Manipulations
before
head
0x100 0
0x104 0x100
0x108 0x104

node0
0x1a0 0
0x1a4 0x1a0
0x1a8 0x1a4

#define QINSERT_BEFORE(head, node, alist)\


do {
\
*(head)->alist.prev = (node);
\
(node)->alist.prev = (head)->alist.prev;
\
(head)->alist.prev = &(node)->alist.next;\
(node)->alist.next = (head);
\
} while (/* */0)

QINSERT_BEFORE(head, node0, alist);

head
0x100 0
0x104 0x1a0
0x108 0x1a4

node0
0x1a0 0
0x1a4 0x1a0
0x1a8 0x104

QNODE Manipulations
before
head
0x100 0
0x104 0x100
0x108 0x104

node0
0x1a0 0
0x1a4 0x1a0
0x1a8 0x1a4

#define QINSERT_BEFORE(head, node, alist)\


do {
\
*(head)->alist.prev = (node);
\
(node)->alist.prev = (head)->alist.prev;
\
(head)->alist.prev = &(node)->alist.next;\
(node)->alist.next = (head);
\
} while (/* */0)

QINSERT_BEFORE(head, node0, alist);

head
0x100 0
0x104 0x1a0
0x108 0x1a4

node0
0x1a0 0
0x1a4 0x100
0x1a8 0x104

QNODE Manipulations
before
head
0x100 0
0x104 0x100
0x108 0x104

node0
0x1a0 0
0x1a4 0x1a0
0x1a8 0x1a4

#define QINSERT_BEFORE(head, node, alist)\


do {
\
*(head)->alist.prev = (node);
\
(node)->alist.prev = (head)->alist.prev;
\
(head)->alist.prev = &(node)->alist.next;\
(node)->alist.next = (head);
\
} while (/* */0)

QINSERT_BEFORE(head, node0, alist);

head
0x100 0
0x104 0x1a0
0x108 0x1a4

node0
0x1a0 0
0x1a4 0x100
0x1a8 0x104

Adding a Third Node


head
0x100 0
0x104 0x1a0
0x108 0x1a4

node0
0x1a0 0
0x1a4 0x100
0x1a8 0x104

node1
0x200 0
0x204 0x200
0x208 0x204

#define QINSERT_BEFORE(head, node, alist)\


do {
\
*(head)->alist.prev = (node);
\
(node)->alist.prev = (head)->alist.prev;
\
(head)->alist.prev = &(node)->alist.next; \
(node)->alist.next = (head);
\
} while (/* */0)

QINSERT_BEFORE(head, node1, alist);

head
0x100 0
0x104 0x1a0
0x108 0x1a4

node0
0x1a0 0
0x1a4 0x100
0x1a8 0x104

node1
0x200 0
0x204 0x200
0x208 0x204

Adding a Third Node


head
0x100 0
0x104 0x1a0
0x108 0x1a4

node0
0x1a0 0
0x1a4 0x100
0x1a8 0x104

node1
0x200 0
0x204 0x200
0x208 0x204

#define QINSERT_BEFORE(head, node1, alist)\


do {
\
*(head)->alist.prev = (node1); \
(1)
(node1)->alist.prev = (head)->alist.prev; \
(head)->alist.prev = &(node1)->alist.next; \
(node1)->alist.next = (head); \
} while (/* */0)

QINSERT_BEFORE(head, node1, alist);

head
0x100 0
0x104 0x1a0
0x108 0x1a4

node0
0x1a0 0
0x1a4 0x200
0x1a8 0x104

(1)

node1
0x200 0
0x204 0x200
0x208 0x204

Adding a Third Node


head
0x100 0
0x104 0x1a0
0x108 0x1a4

node0
0x1a0 0
0x1a4 0x100
0x1a8 0x104

node1
0x200 0
0x204 0x200
0x208 0x204

#define QINSERT_BEFORE(head, node1, alist)\


do {
\
*(head)->alist.prev = (node1); \
(2)
(node1)->alist.prev = (head)->alist.prev; \
(head)->alist.prev = &(node1)->alist.next; \
(node1)->alist.next = (head); \
} while (/* */0)

QINSERT_BEFORE(head, node1, alist);

head
0x100 0
0x104 0x1a0
0x108 0x1a4

node0
0x1a0 0
0x1a4 0x200
0x1a8 0x104

(1)

node1
0x200 0
0x204 0x200
0x208 0x1a4

(2)

Adding a Third Node


head
0x100 0
0x104 0x1a0
0x108 0x1a4

node0
0x1a0 0
0x1a4 0x100
0x1a8 0x104

node1
0x200 0
0x204 0x200
0x208 0x204

#define QINSERT_BEFORE(head, node1, alist)\


do {
\
*(head)->alist.prev = (node1); \
(1)
(2)
(node1)->alist.prev = (head)->alist.prev; \
(3)
(head)->alist.prev = &(node1)->alist.next; \
(node1)->alist.next = (head); \
} while (/* */0)

QINSERT_BEFORE(head, node1, alist);

head
0x100 0
0x104 0x1a0
0x108 0x204

node0
0x1a0 0
0x1a4 0x200
0x1a8 0x104

(1)

node1
0x200 0
0x204 0x200
0x208 0x1a4

(3)
(2)

Adding a Third Node


head
0x100 0
0x104 0x1a0
0x108 0x1a4

node0
0x1a0 0
0x1a4 0x100
0x1a8 0x104

node1
0x200 0
0x204 0x200
0x208 0x204

#define QINSERT_BEFORE(head, node1, alist)\


do {
\
*(head)->alist.prev = (node1); \
(1)
(2)
(node1)->alist.prev = (head)->alist.prev; \
(3)
(head)->alist.prev = &(node1)->alist.next; \
(4)
(node1)->alist.next = (head); \
} while (/* */0)

QINSERT_BEFORE(head, node1, alist);


(4)
head
0x100 0
0x104 0x1a0
0x108 0x204

node0
0x1a0 0
0x1a4 0x200
0x1a8 0x104

(1)

node1
0x200 0
0x204 0x100
0x208 0x1a4

(3)
(2)

Removing a Node
head
0x100 0
0x104 0x1a0
0x108 0x204

node0
0x1a0 0
0x1a4 0x200
0x1a8 0x104

node1
0x200 0
0x204 0x100
0x208 0x1a4

#define QREMOVE(node, alist)


\
do {
\
(1) *((node)->alist.prev) = (node)->alist.next;
\
(2) ((node)->alist.next)->alist.prev = (node)->alist.prev;\
(3) (node)->alist.next = (node);
\
(4) (node)->alist.prev = &((node)->alist.next); \
} while ( /* */ 0)

QREMOVE(node0, alist);
head
0x100 0
0x104 ??
0x108 ??

node0
0x1a0 0
0x1a4 ??
0x1a8 ??

node1
0x200 0
0x204 ??
0x208 ??

Removing a Node
head
0x100 0
0x104 0x1a0
0x108 0x204

node0
0x1a0 0
0x1a4 0x200
0x1a8 0x104

node1
0x200 0
0x204 0x100
0x208 0x1a4

#define QREMOVE(node, alist)


\
do {
\
*((node)->alist.prev) = (node)->alist.next;
\
((node)->alist.next)->alist.prev = (node)->alist.prev;\
(node)->alist.next = (node); \
(node)->alist.prev = &((node)->alist.next);
\
} while ( /* */ 0)

QREMOVE(node0, alist);

head
0x100 0
0x104 0x1a0
0x108 0x204

node0
0x1a0 0
0x1a4 0x200
0x1a8 0x104

node1
0x200 0
0x204 0x100
0x208 0x1a4

Removing a Node
head
0x100 0
0x104 0x1a0
0x108 0x204

node0
0x1a0 0
0x1a4 0x200
0x1a8 0x104

node1
0x200 0
0x204 0x100
0x208 0x1a4

#define QREMOVE(node0, alist)


\
do {
\
(1) *((node0)->alist.prev) = (node0)->alist.next; \
((node0)->alist.next)->alist.prev = (node0)->alist.prev;\
(node0)->alist.next = (node0);
\
(node0)->alist.prev = &((node0)->alist.next); \
} while ( /* */ 0)

QREMOVE(node0, alist);

head
0x100 0
0x104 0x200
0x108 0x204

(1)

node0
0x1a0 0
0x1a4 0x200
0x1a8 0x104

node1
0x200 0
0x204 0x100
0x208 0x1a4

Removing a Node
head
0x100 0
0x104 0x1a0
0x108 0x204

node0
0x1a0 0
0x1a4 0x200
0x1a8 0x104

node1
0x200 0
0x204 0x100
0x208 0x1a4

#define QREMOVE(node0, alist)


\
do {
\
*((node0)->alist.prev) = (node0)->alist.next; \
(2) ((node0)->alist.next)->alist.prev = (node0)->alist.prev;\
(node0)->alist.next = (node0);
\
(node0)->alist.prev = &((node0)->alist.next);
\
} while ( /* */ 0)

QREMOVE(node0, alist);

head
0x100 0
0x104 0x200
0x108 0x204

node0
0x1a0 0
0x1a4 0x200
0x1a8 0x104

node1
0x200 0
0x204 0x100
0x208 0x104

(2)

Removing a Node
head
0x100 0
0x104 0x1a0
0x108 0x204

#define QREMOVE(node0, alist)


\
do {
\
*((node0)->alist.prev) = (node0)->alist.next; \
((node0)->alist.next)->alist.prev = (node0)->alist.prev;\
(3) (node0)->alist.next = (node0);
\
(node0)->alist.prev = &((node0)->alist.next);
\
} while ( /* */ 0)

node0
0x1a0 0
0x1a4 0x200
0x1a8 0x104

node1
0x200 0
0x204 0x100
0x208 0x1a4

QREMOVE(node0, alist);

head
0x100 0
0x104 0x200
0x108 0x204

(3)

node0
0x1a0 0
0x1a4 0x1a0
0x1a8 0x104

node1
0x200 0
0x204 0x100
0x208 0x104

Removing a Node
head
0x100 0
0x104 0x1a0
0x108 0x204

node0
0x1a0 0
0x1a4 0x200
0x1a8 0x104

node1
0x200 0
0x204 0x100
0x208 0x1a4

#define QREMOVE(node0, alist)


\
do {
\
*((node0)->alist.prev) = (node0)->alist.next; \
((node0)->alist.next)->alist.prev = (node0)->alist.prev;\
(node0)->alist.next = (node0);
\
(4) (node0)->alist.prev = &((node0)->alist.next); \
} while ( /* */ 0)

QREMOVE(node0, alist);

head
0x100 0
0x104 0x200
0x108 0x204

(4)

node0
0x1a0 0
0x1a4 0x1a0
0x1a8 0x1a4

node1
0x200 0
0x204 0x100
0x208 0x104

Solution to Removing a Node


head
0x100 0
0x104 0x1a0
0x108 0x204

node0
0x1a0 0
0x1a4 0x200
0x1a8 0x104

node1
0x200 0
0x204 0x100
0x208 0x1a4

#define QREMOVE(node, alist)


\
do {
\
(1) *((node)->alist.prev) = (node)->alist.next;
\
(2) ((node)->alist.next)->alist.prev = (node)->alist.prev;\
(3) (node)->alist.next = (node);
\
(4) (node)->alist.prev = &((node)->alist.next); \
} while ( /* */ 0)

QREMOVE(node0, alist);

head
0x100 0
0x104 0x200
0x108 0x204

node0
0x1a0 0
0x1a4 0x1a0
0x1a8 0x1a4

node1
0x200 0
0x204 0x100
0x208 0x104

Functions

Always use function prototypes


int myfunc (char *, int, struct MyStruct *);
int myfunc_noargs (void);
void myfunc_noreturn (int i);
C and C++ are call by value, copy of parameter passed to function

C++ permits you to specify pass by reference


if you want to alter the parameter then pass a pointer to it (or use references in
C++)

If performance is an issue then use inline functions, generally better and safer
than using a macro. Common convention

define prototype and function in header or name.i file


static inline int myinfunc (int i, int j);
static inline int myinfunc (int i, int j) { ... }

Basic Types and Operators

Basic data types

Types: char, int, float and double


Qualifiers: short, long, unsigned, signed, const

Constant: 0x1234, 12, Some string

Enumeration:

Names in different enumerations must be distinct


enum WeekDay_t {Mon, Tue, Wed, Thur, Fri};
enum WeekendDay_t {Sat = 0, Sun = 4};

Arithmetic: +, -, *, /, %

prefix ++i or --i ; increment/decrement before value is used


postfix i++, i--; increment/decrement after value is used

Relational and logical: <, >, <=, >=, ==, !=, &&, ||

Bitwise: &, |, ^ (xor), <<, >>, ~(ones complement)

Operator Precedence (from C a Reference Manual, 5


Pr
ec
ed
en
ce

th

Edition)

Associates

Tokens

Operator

Class

Pr
ec
ed
en
ce

primary

n/a

(type)

casts

unary

14

right-to-left

subscripting

postfix

left-to-right

* / %

multiplicative

binary

13

left-to-right

f(...)

function call

postfix

left-to-right

+ -

additive

binary

12

left-to-right

direct selection

postfix

left-to-right

<< >>

left, right shift

binary

11

left-to-right

->

indirect selection

postfix

left to right

< <= > >=

relational

binary

10

left-to-right

++ --

increment, decrement

postfix

left-to-right

== !=

equality/ineq.

binary

left-to-right

(type){init}

compound literal

postfix

left-to-right

&

bitwise and

binary

left-to-right

increment, decrement

prefix

right-to-left

bitwise xor

binary

left-to-right

sizeof

size

unary

right-to-left

bitwise or

binary

left-to-right

bitwise not

unary

right-to-left

&&

logical and

binary

left-to-right

logical not

unary

right-to-left

||

logical or

binary

left-to-right

- +

negation, plus

unary

right-to-left

?:

conditional

ternary

right-to-left

&

address of

unary

right-to-left

indirection
(dereference)

unary

right-to-left

= += -=
*= /= %=
&= ^= |=
<<= >>=

assignment

binary

right-to-left

sequential eval.

binary

left-to-right

Tokens

Operator

Class

names,
literals

simple tokens

a[k]

++

--

16

15

Associates

Structs and Unions

structures
struct MyPoint {int x, int y};
typedef struct MyPoint MyPoint_t;
MyPoint_t point, *ptr;
point.x = 0;point.y = 10;
ptr = &point; ptr->x = 12; ptr->y = 40;

unions
union MyUnion {int x; MyPoint_t pt;
struct {int 3; char c[4]} S;};
union MyUnion x;
Can only use one of the elements. Memory will be
allocated for the largest element

Conditional Statements (if/else)

if (a < 10)
printf(a is less than 10\n);
else if (a == 10)
printf(a is 10\n);
else
printf(a is greater than 10\n);
If you have compound statements then use brackets (blocks)
if (a < 4 && b > 10) {
c = a * b; b = 0;
printf(a = %d, a\s address = 0x%08x\n, a, (uint32_t)&a);
} else {
c = a + b; b = a;
}

These two statements are equivalent:


if (a) x = 3; else if (b) x = 2; else x = 0;
if (a) x = 3; else {if (b) x = 2; else x = 0;}

Is this correct?
if (a) x = 3; else if (b) x = 2;
else (z) x = 0; else x = -2;

Conditional Statements (switch)


int c = 10;
switch (c) {
case 0:
printf(c is 0\n);
break;
...
default:
printf(Unknown value of c\n);
break;
}

What if we leave the break statement out?


Do we need the final break statement on the default case?

Loops
for (i = 0; i < MAXVALUE; i++) {
dowork();
}
while (c != 12) {
dowork();
}
do {
dowork();
} while (c < 12);

flow control

break exit innermost loop


continue perform next iteration of loop

Note, all these forms permit one statement to be executed. By


enclosing in brackets we create a block of statements.

Building your program

For all labs and programming assignments:

you must supply a make file


you must supply a README file that describes the
assignment and results. This must be a text file, no MS
word.
of course the source code and any other libraries or
utility code you used
you may submit plots, they must be postscript or pdf

make and Makefiles, Overview

Why use make?

convenience of only entering compile directives once


make is smart enough (with your help) to only compile and link modules that have
changed or which depend on files that have changed
allows you to hide platform dependencies
promotes uniformity
simplifies my (and hopefully your) life when testing and verifying your code

A makefile contains a set of rules for building a program


target ... : prerequisites ...
command
...

Static pattern rules.

each target is matched against target-pattern to derive stem which is used to


determine prereqs (see example)
targets ... : target-pattern : prereq-patterns ...
command
...

Makefiles

Defining variables
MyOPS := -DWTH
MyDIR ?= /home/fred
MyVar
= $(SHELL)
Using variables
MyFLAGS := $(MyOPS)
Built-in Variables

$@ = filename of target
$< = name of the first prerequisites

Patterns

use % character to determine stem


foo.o matches the pattern %.o with foo as the stem.
foo.o moo.o : %.o : %.c # says that foo.o depends on foo.c

Example Makefile for wulib


Makefile.inc
# Makefile.inc
# Contains common definitions
MyOS
MyID
MyHost
WARNSTRICT

WARNLIGHT
WARN
ALLFLGS

:= $(shell uname -s)


:= $(shell whoami)
:= $(shell hostname)
:= -W \
-Wstrict-prototypes \
-Wmissing-prototypes
:= -Wall
:= ${WARNLIGHT}
:= -D_GNU_SOURCE \
-D_REENTRANT \
-D_THREAD_SAFE

Makefile
# Project specific
include ../Makefile.inc
INCLUDES = ${WUINCLUDES} I.
LIBS
= ${WILIBS} ${OSLIBS}
CFLAGS
= ${WUCLFAGS} DWUDEBUG
CC
= ${WUCC}
HDRS
CSRCS
SRCS
COBJS
OBJS
CMDS

APPCFLGS

WUCC
WUCFLAGS

WUINCLUDES
WULIBS

=
$(WARN)

$(ALLFLGS) \
all :

$(OBJDIR) $(CMDS)

:= gcc
:= -DMyOS=$(MyOS) \
$(OSFLAGS) \
$(ALLFLGS) $(WARN)

install : all

:=
:= -lm

$(OBJS)

ifeq (${MyOS), SunOS)


OSLIBS+= -lrt
endif

:= util.h
:= testapp1.c testapp2.c
:= util.c callout.c
= $(addprefix ${OBJDIR}/, \
$(patsubst %.c,%.o,$(CSRCS)))
= $(addprefix ${OBJDIR}/, \
$(patsubst %.c,%.o,$(SRCS)))
= $(addprefix ${OBJDIR}/, $(basename $(CSRCS)))

$(OBJDIR) :
mkdir $(OBJDIR)
$(COBJS) : ${OBJDIR}/%.o : %.c $(HDRS)
${CC} ${CFLAGS} ${INCLUDES} o $@ -c $<

$(CMDS) : ${OBJDIR}/% : ${OBJDIR}/%.o $(OBJS)


${CC} ${CFLAGS} -o $@ $@.o ${LIBS}
chmod 0755 $@
clean :
/bin/rm -f $(CMDS) $(OBJS)

Project Documentation

README file structure

Section A: Introduction
describe the project, paraphrase the requirements and state your understanding of
the assignments value.
Section B: Design and Implementation
List all files turned in with a brief description for each. Explain your design and
provide simple psuedo-code for your project. Provide a simple flow chart of you
code and note any constraints, invariants, assumptions or sources for reused code or
ideas.
Section C: Results
For each project you will be given a list of questions to answer, this is where you do
it. If you are not satisfied with your results explain why here.
Section D: Conclusions
What did you learn, or not learn during this assignment. What would you do
differently or what did you do well.

Attacking a Project

Requirements and scope: Identify specific requirements and or goals. Also note
any design and/or implementation environment requirements.

knowing when you are done, or not done


estimating effort or areas which require more research
programming language, platform and other development environment issues

Approach: How do you plan to solve the problem identified in the first step.
Develop a prototype design and document. Next figure out how you will verify
that you did satisfy the requirements/goals. Designing the tests will help you to
better understand the problem domain and your proposed solution
Iterative development: It is good practice to build your project in small pieces.
Testing and learning as you go.
Final Touches: Put it all together and run the tests identified in the approach
phase. Verify you met requirements. Polish you code and documentation.
Turn it in:

You might also like