Slide: 1 CAMP 06: Maturing Minds Programming in C Recap Camp 06 Maturing Minds.

Presentation on theme: "Slide: 1 CAMP 06: Maturing Minds Programming in C Recap Camp 06 Maturing Minds."— Presentation transcript:

Slide: 1 CAMP 06: Maturing Minds Programming in C Recap Camp 06 Maturing Minds

Slide: 2 CAMP 06: Maturing Minds Goals We review different constructs of C language We discuss typical syntactic and semantic pitfalls We discuss some complex programming concepts like function pointers We discuss some guidelines that will help you in writing good C code

Slide: 3 CAMP 06: Maturing Minds How big is an integer? long is not always 32 bits. int is not always 32 bits. The only truth is: sizeof(char) <= sizeof(short) <= sizeof(int) <= sizeof(long) sizeof(char) is always 1. Sizes of float, double variables are implementation dependent.

Slide: 4 CAMP 06: Maturing Minds What happens when an integer operation overflows? If either operand is unsigned, the result is unsigned and is defined to be modulo 2 n. If both operands are signed, the result is undefined. a and b are two big integers which are multiplied to obtain a number that may be stored in a long. The following, however, is incorrect. long c = a * b; //Why? Integer overflow // a and b are int [positive] if ((a + b) < 0) complain(); //might not work if ((int) ((unsigned)a + (unsigned)b) < 0) complain(); // will work

Slide: 5 CAMP 06: Maturing Minds Are characters signed? Whether it is signed or unsigned is implementation dependent. Still, for programming purposes char is neither signed char nor unsigned char.

Slide: 6 CAMP 06: Maturing Minds Operator precedence Operator precedence may give surprises sometimes. if (flags & OF_FLAG != 1) {...}; // what does this mean? != binds more tightly than &. if ((flags & OF_FLAG) != 1) {...}; Use braces properly in expressing yourself

Slide: 7 CAMP 06: Maturing Minds Operator precedence Two int vars, h and l are in [0,15] range. r is formed as (h,l). r = h<<4 + l; // is it correct? r = h << (4 + l); //same as above + binds more tightly than <<. Dont trust spaces!!! Trust braces. r = (h << 4) + l; //correct

Slide: 8 CAMP 06: Maturing Minds Expression evaluation sequence i = 0; while ( i < n) { y[i] = x[i++]; } There is no guarantee that address of y[i] will be evaluated before i is incremented. Only operators &&, ||, ?:, and, specify an order of evaluation. i = 0; // This works while (i < n) { y[i] = x[i]; ++i; } Keep things simple and they will be reliable. Expression order for function parameters.

Slide: 9 CAMP 06: Maturing Minds Shift operators In right shift are vacated bits filled with zeros or sign bit? If item is unsigned zeros are filled in. If item is signed, implementation is permitted to fill either zero, or sign bit.

Slide: 10 CAMP 06: Maturing Minds Shift operators What values are permitted for a shift count? For an n-bit number Shift count >= 0 Shift count < n [strictly] Otherwise result is undefined !

Slide: 11 CAMP 06: Maturing Minds Shift operators Is right shift same as divide by 2? Well mostly yes. For signed numbers sign bit should be copied in vacated bits. But not Always! Try this! (-1)>>1

Slide: 12 CAMP 06: Maturing Minds Are Assignment statements expressions? Is the following statement valid? a = b = c+d*e; Assignment statements are expressions as well. Expressions have operators, operands and a result. The result (like operators and operands) do have a type and a value. The value and type of an expression is the same as the type and value of the lhs of an expression. You must be familiar with the following code segments if (a = (b+c)) …. while (ch = getc()) ….

Slide: 13 CAMP 06: Maturing Minds Watch those semicolons! struct { int x; } f() {... } if (x[i] > big); big = x[i]; Dont trust implicit return types. Be careful of semicolons.

Slide: 14 CAMP 06: Maturing Minds The switch statement switch (color) { case 1: printf ("red"); case 2: printf("yellow"); break; case 3: printf("blue"); } Be careful of break. It is weakness as well as strength of C. case SUBTRACT: opnd2 = -opnd2; /* falls through*/ case ADD:... Use comments if a case falls through into another.

Slide: 15 CAMP 06: Maturing Minds The dangling else if (x == 0) if (y == 0) error(); else { z = x + y; f(&z); } if (x == 0) { if (y == 0) { error(); } else { z = x + y; f(&z); } Indentation is good as people understand it well. Braces are necessary as compilers understand it well.

Slide: 16 CAMP 06: Maturing Minds Functions and Parameter Passing Functions are also types to the compilers Type of a function comprises of the signature and the return type. Function names are identifiers. Parameters are passed in C using call by value. This value may be an integer, an array, a structure or a pointer.

Slide: 17 CAMP 06: Maturing Minds Call by Value There is no mechanism called call by address. The value passed may legitimately be an address and therefore the type of the formal parameter is pointer. The value of the actual parameter can never be changed from within a function invocation. What we change at the most is what has been pointed to by a formal parameter. Change in the formal parameter, in case the formal parameter is an address, can never be reflected in the value of the actual parameter.

Slide: 18 CAMP 06: Maturing Minds Array & Pointer These are two separate data types. Array name is an l- value that cannot be modified. Initialization of an array has a different syntax than initialization of a pointer. Distinguish between the two. char a[] = "string literal"; char *p = "string literal"; char *p = "hello, world!"; p[0] = 'H'; // This code may crash Pointer to an array int (*ap)[N]; /* N is a constant expression. Passing statically and dynamically allocated multi- dimensional array in functions.

Slide: 19 CAMP 06: Maturing Minds Passing 1-D Arrays to Functions Consider a 1-d array int a[10] has to be passed to a function. Which of the following functions have the correct declaration? void f (int *x) void f (int x[5]) void f (int x[10]) void f (int x[12])

Slide: 20 CAMP 06: Maturing Minds Passing 2-D Arrays to Functions Consider a 1-d array int a[10][20] has to be passed to a function. Which of the following functions have the correct declaration? void f (int * *x) void f (int *x[20]) void f (int (*x)[10]) void f (int (*x)[20]) void f (int x[10][20])

Slide: 21 CAMP 06: Maturing Minds Structure & Alignment Structure is a type. Only operators valid on a structure are: =, &,. Two structures cannot be compared. sizeof of a structure is most often more than the individual sizeof of its members struct example { char c; int n; } size of example is not 1+4. Due to word alignment Word alignment is important for efficient machine level data storage and retrieval.

Slide: 22 CAMP 06: Maturing Minds Structure & Alignment Padding for word alignment cannot be turned off in a universal manner Determining the byte offset of a field within a structure ANSI C defines a offsetof() macro, which should be used if available; see. If you don't have it, one possible implementation is #define offsetof(type, mem) ((size_t) ((char *)&((type *)0)->mem - (char *)(type *)0)) This implementation is not 100% portable; some compilers may legitimately refuse to accept it. Build a table of names and offsets, using the offsetof() macro. The offset of field b in struct a is offsetb = offsetof(struct a, b) If structp is a pointer to an instance of this structure, and field b is an int (with offset as computed above), b's value can be set indirectly with *(int *)((char *)structp + offsetb) = value;

Slide: 23 CAMP 06: Maturing Minds NULL pointers It must never be dereferenced. The NULL pointer is not a null string. if (p == (char *) 0)... //ok if (strcmp(p, (char *)0) == 0)... //invalid printf(p); //invalid if p is null pointer

Slide: 24 CAMP 06: Maturing Minds NULL pointer NULL pointer is a literal for every pointer type. However, the type of NULL is different in different contexts. NULL and NULL pointer are not the same. NULL is a macro that is defined to be 0. A constant 0 in a pointer context is converted into a null pointer at compile time. That is, in an initialization, assignment, or comparison when one side is a variable or an expression of pointer type, the compiler can tell that a constant 0 on the other side requests a null pointer, and generate the correctly-typed null pointer value. Therefore, the following fragments are perfectly legal char *p = 0; if(p != 0)

Slide: 25 CAMP 06: Maturing Minds NULL pointers in Functions An argument being passed to a function is not necessarily recognizable as a pointer context, and the compiler may not be able to tell that an unadorned 0 means a null pointer. To generate a null pointer in a function call context, an explicit cast may be required, to force the 0 to be recognized as a pointer. Suppose NULL is defined as follows: #define NULL ((char *)0) wouldn't that make function calls which pass an uncast NULL work? Not in general.

Slide: 26 CAMP 06: Maturing Minds getchar() returns an integer #include int main() { char c; while ((c = getchar()) != EOF) { putchar(c); } Catch the bug!!! char c cant hold EOF, use int c instead.

Slide: 27 CAMP 06: Maturing Minds The preprocessor Important for following major reasons We can change all instances of a particular quantity For defining macros that appear to be functions, but do not have the function calling overhead

Slide: 28 CAMP 06: Maturing Minds Macros are not functions In a macro, an operand that is used twice may be evaluated twice. Expressions like x[i++] lead to side effects. Avoid side effects! #define MAX(a,b) (((a) > (b)) ? (a) : (b)) biggest = x[0]; i = 1; while (i < n) biggest = MAX(biggest, x[i++]); // wrong??

Slide: 29 CAMP 06: Maturing Minds Understanding Declarations int *gi();() binds more tightly than *. *gi() is same as*(gi()) *(gi()) is of type int => gi() is a pointer to int, => gi is a function that returns pointer to int. int (*hi)();(*hi)() is int => (*hi) is a function that returns int => hi is a pointer to a function that returns int

Slide: 30 CAMP 06: Maturing Minds Understanding typecasts If you know how to declare a type, it is easy to write a cast for that type. TypeDeclarationCast Pointer to function that returns intint (*fp)()int (*)() Pointer to function that returns nothingvoid (*fp)()void (*)()

Slide: 31 CAMP 06: Maturing Minds Try it yourself There is a function void f(). Its address is stored at location 0x0 in memory. Write a C statement to execute this function by taking address from 0x0. What is meant by the following declaration? int signal( int (*)(int), int);

Slide: 32 CAMP 06: Maturing Minds Function pointers Variables which point to the address of a function We can implement call-backs Complicated syntax Use it only when you need it!

Slide: 33 CAMP 06: Maturing Minds A Generic Search Problem Suppose that we have to search one item from a list (dynamic array) of such items. We do not know the type of the item when we write the code. Pseudo code for (int i; i < n; i++) { if (equal(a[i], k) return i; } Issues: What is the type of the array a, variable k? If a is declared as void *, *(a+i) is not defined. How can we manage to write equal function? back

Slide: 34 CAMP 06: Maturing Minds Solution to Generic Search Problem Solution to the first two issues: Formal parameter a is of type void *. However actual parameter for a may be a pointer to a list of any thing (e.g., rectangle, employee etc.) The caller of generic_search has to supply the size of the type that the actual parameter of a points to. Formal parameter of k is of type void *. The caller ensures that the actual parameter for a and k are the same. for (i = 0; i < n; i++) { equal ( (void *)((char*)a + i *size), k) return i; } back

Slide: 35 CAMP 06: Maturing Minds Using Function pointers equal function can not be written by the implementer of generic_search. equal function can be written by the designer and developer of types such as rectangle. The prototype for equalmust be fixed and may be int XXX(void *, void *). The actual function XXX may be passed to the generic_search routine by the caller. int generic_search( void* a, int n, void *k, int size, int (*fp)(void *, void *)) { for (i = 0; i < n; i++) { if ((*fp)( (void *)((char*)a + i *size), k) == 0) return i; }

Slide: 36 CAMP 06: Maturing Minds Check external types yourself file1.c extern int n; file2.c char n; Compiler compiles single file, doesnt know contents of others. Linkers may not know about data types. The program may work just by coincidence!!

Slide: 37 CAMP 06: Maturing Minds Reentrancy For the code to be re-entrant, each invocation must use its own copy of any modifiable data. Static variables should not be used. Global variables should not be used [except constants] Automatic variables should be used. No calls to a non-reentrant code should be made.

Similar presentations