Understand more about C

55
Understand more about C 2016 [email protected]

Transcript of Understand more about C

Page 1: Understand more about C

Understand more about C

2016

[email protected]

Page 2: Understand more about C

2

An Example

• What will happen if you try to compile, link and run this program?

int main(){ int a = 42; printf(“%d\n”, a);}

You must #include , add a return 0 and then it will compile and link. When executed it will print the value 42 on the screen.

Page 3: Understand more about C

3

An Example

• What will happen if you try to compile, link and run this program?

int main(){ int a = 42; printf(“%d\n”, a);}

You probably want to #include which has an explicit declaration of printf(). The program will compile, link and run, and it will write the number 42 followed by a newline to the standard output stream.

A proper C compiler will create an implicit declaration for the function printf(), compile this code into an object file.

And when linked with a standard library, it will find a definition of printf()that accidentally will match the implicit declaration.

So the program above will actually compile, link and run.

Page 4: Understand more about C

4

An Example

• What will happen if you try to compile, link and run this program?

int main(){ int a = 42; printf(“%d\n”, a);}

If this is C99, the exit value is defined to indicate success to the runtime environment, just like in C++98, but for older versions of C, like ANSI C and K&R, the exit value from this program will be some undefined garbage value.

But since return values are often passed in a register I would not be surprised if the garbage value happens to be 3... since printf() will return 3, the number of characters written to standard out.

Page 5: Understand more about C

5

An Example

• What will happen if you try to compile, link and run this program?

int main(){ int a = 42; printf(“%d\n”, a);}

And talking about C standards... if you want to show that you care about C programming, you should use int main(void) as your entry point - since the standard says so.

Using void to indicate no parameters is essential for declarations in C, eg a declaration ‘int f();’, says there is a function f that takes any number of arguments. While you probably meant to say ‘int f(void);’. Being explicit by using void also for function definitions does not hurt.

Page 6: Understand more about C

6

An Example

• Here is what I get when compiling, linking and running the above program on my machine

$ gcc -std=c89 hello1.c$ ./a.out42$ echo $?3

$ gcc -std=c99 hello1.c$ ./a.out42$ echo $?0

#include <stdio.h>int main(void){ int a = 42; printf(“%d\n”, a);}

The default mode for C is now -std=gnu11 instead of -std=gnu89 in GCC-5

Page 7: Understand more about C

7

Would it be useful if most of your colleagues have a deep understanding of the C programming language they are using?

https://algoritmaveprogramlama.files.wordpress.com/2013/10/c_pic.png

Page 8: Understand more about C

8

More C examples

• What is the result of following C code?

#include <stdio.h>void foo(void){

int a = 3;++a;printf("%d\

n", a);}int main(void){

foo();foo();foo();

}

Page 9: Understand more about C

9

More C examples

• What is the result of following C code?

#include <stdio.h>void foo(void){

static int a = 3;

++a;printf("%d\

n", a);}int main(void){

foo();foo();foo();

}

Page 10: Understand more about C

10

More C examples

• What is the result of following C code?

#include <stdio.h>void foo(void){

static int a;++a;printf("%d\

n", a);}int main(void){

foo();foo();foo();

}

Page 11: Understand more about C

11

More C examples

• What is the result of following C code?

#include <stdio.h>void foo(void){

int a;++a;printf("%d\

n", a);}int main(void){

foo();foo();foo();

}

Page 12: Understand more about C

12

More C examples

• What is the result of following C code?

#include <stdio.h>static int a;void foo(void){

++a;printf("%d\

n", a);}int main(void){

foo();foo();foo();

}

Page 13: Understand more about C

13

More C examples

• What is the result of following C code?

#include <stdio.h>int a;void foo(void){

++a;printf("%d\

n", a);}int main(void){

foo();foo();foo();

}

Page 14: Understand more about C

14

More C examples

• Can you explain this behavior?

#include <stdio.h>void foo(void){ int a; printf("%d\n", a);}void bar(void){ int a = 42;}int main(void){ bar(); foo();}

$ gcc hello3.c && ./a.out42

$ gcc –O2 hello3.c && ./a.out0

Page 15: Understand more about C

15

More C examples

• What about this code snippet?

#include <stdio.h>void foo(void){ int a = 41; a = a++; printf("%d\n", a);}int main(void){ foo();}

Page 16: Understand more about C

16

More C examples

• What about this code snippet?

#include <stdio.h>

int b(void) { puts(“3”); return 3; }int c(void) { puts(“4”); return 4; }

int main(void){ int a = b() + c(); printf(“%d\n”, a);}

Page 17: Understand more about C

17

More C examples

• What do these code snippets print?

int a=41; a++; printf("%d\n", a);

int a=41; a++ & printf("%d\n", a);

int a=41; a++ && printf("%d\n", a);

int a=41; if (a++ < 42) printf("%d\n", a);

int a=41; a = a++; printf("%d\n", a);

Page 18: Understand more about C

18

SEQUENCE POINT

Page 19: Understand more about C

19

Sequence point

• Sequence point– https://en.wikipedia.org/wiki/Sequence_point– A sequence point is a point in the program's execution sequence where all

previous side-effects shall have taken place and where all subsequent side-effects shall not have taken place

– A lot of developers think C has many sequence points

– The reality is that C has very few sequence points

– This helps to maximize optimization opportunities for the compiler

Page 20: Understand more about C

20

Sequence point

– Between the previous and next sequence point an object shall have its stored value modified at most once by the evaluation of an expression.

– Furthermore, the prior value shall be read only to determine the value to be stored.

Page 21: Understand more about C

21

Sequence point

• In C and C++, sequence points occur in the following places– Between evaluation of the left and right operands of the && (logical AND), ||

(logical OR) (as part of short-circuit evaluation), and comma operators.• For example, in the expression *p++ != 0 && *q++ != 0, all side effects of the sub-

expression *p++ != 0 are completed before any attempt to access q.– Between the evaluation of the first operand of the ternary "question-mark"

operator and the second or third operand.• For example, in the expression a = (*p++) ? (*p++) : 0 there is a sequence point after the

first *p++, meaning it has already been incremented by the time the second instance is executed.

– At the end of a full expression.• This category includes expression statements (such as the assignment a=b;), return

statements, the controlling expressions of if, switch, while, or do-while statements, and all three expressions in a for statement.

Page 22: Understand more about C

22

Sequence point

• In C and C++, sequence points occur in the following places– Before a function is entered in a function call.

• The order in which the arguments are evaluated is not specified, but this sequence point means that all of their side effects are complete before the function is entered.

• In the expression f(i++) + g(j++) + h(k++), f is called with a parameter of the original value of i, but i is incremented before entering the body of f. Similarly, j and k are updated before entering g and h respectively.

• However, it is not specified in which order f(), g(), h() are executed, nor in which order i, j, k are incremented. Variables j and k in the body of f may or may not have been already incremented. Note that a function call f(a,b,c) is not a use of the comma operator and the order of evaluation for a, b, and c is unspecified.

Page 23: Understand more about C

23

Sequence point

• In C and C++, sequence points occur in the following places– At a function return, after the return value is copied into the calling

context. (This sequence point is only specified in the C++ standard; it is present only implicitly in C)

– At the end of an initializer• for example, after the evaluation of 5 in the declaration int a = 5;.

– Between each declarator in each declarator sequence• for example, between the two evaluations of a++ in int x = a++, y = a++.

– Aftei the action associated with input/output conversion format specifier• For example, in the expression printf(“foo %n %d”, &a, 42), there is a sequence

point after the %n is evaluated before printing 42

Page 24: Understand more about C

24

POINTERS

Page 25: Understand more about C

25

Pointers vs. Arrays

• What is the output of following code?

#include <stdio.h>#include <string.h>int main(){ char *p = "hello"; char q[] = "hello"; printf("%zu\n", sizeof(p)); printf("%zu\n", sizeof(q)); printf("%zu\n", strlen(p)); printf("%zu\n", strlen(q));

return 0;}

Page 26: Understand more about C

26

Pointers vs. Arrays

• What is the output of following code?

#include <stdio.h>#include <string.h>int main(){ char *p = "hello"; char q[] = "hello"; printf("%zu\n", sizeof(p)); printf("%zu\n", sizeof(q)); printf("%zu\n", strlen(p)); printf("%zu\n", strlen(q));

return 0;}

• the sizeof operator• sizeof(array) returns the amount of

memory used by all elements in array• sizeof(pointer) only returns the amount of

memory used by the pointer variable itself• the & operator

• &array is an alias for &array[0] and returns the address of the first element in array

• &pointer returns the address of pointer

Page 27: Understand more about C

27

Pointers vs. Arrays

• What is the output of following code?

#include <stdio.h>#include <string.h>int main(){ char *p = "hello"; char q[] = "hello"; printf("%zu\n", sizeof(p)); printf("%zu\n", sizeof(q)); printf("%zu\n", strlen(p)); printf("%zu\n", strlen(q));

return 0;}

• a string literal initialization of a character array• char array[] = “abc” sets the first four

elements in array to ‘a’, ‘b’, ‘c’, and ‘\0′• char *pointer = “abc” sets pointer to the

address of the “abc” string (which may be stored in read-only memory and thus unchangeable)

Page 28: Understand more about C

28

Pointers vs. Arrays

• What is the output of following code?

#include <stdio.h>#include <string.h>int main(){ char *p = "hello"; char q[] = "hello"; printf("%zu\n", sizeof(p)); printf("%zu\n", sizeof(q)); printf("%zu\n", strlen(p)); printf("%zu\n", strlen(q));

return 0;}

• pointer variable can be assigned a value whereas array variable cannot be

• arithmetic on pointer variable is allowed whereas array variable is not

Page 29: Understand more about C

29

Pointers vs. Arrays

• What is the output of following code?

#include <stdio.h>#include <string.h>void foo(char *p) { printf("%zu\n", sizeof(p)); printf("%zu\n", strlen(p));}void bar(char q[]) { printf("%zu\n", sizeof(q)); printf("%zu\n", strlen(q));}int main() { foo("hello"); bar("hello"); return 0;}

* arrays passed to functions are converted to pointers

Page 30: Understand more about C

30

SIZEOF

Page 31: Understand more about C

31

Example of sizeof

• What about this code snippet?

#include <stdio.h>struct X { int a; char b; int c; };

int main(void){ printf("%zu\n", sizeof(int)); printf("%zu\n", sizeof(char)); printf("%zu\n", sizeof(struct X));}

It all depends on the platform and the compile time options provided. The only thing we know for sure is that sizeof char is 1

4112

with -fpack-struct option419

It is very expensive to work on subword data types, so the compiler will optimize the code by making sure that c is on a word boundary by adding some padding.

Suppose the program is on a 64-bit machine running in 32-bit compatibility mode

Page 32: Understand more about C

32

Example of sizeof

• What about this code snippet?

#include <stdio.h>struct X { int a; char b; int c; char d; };

int main(void){ printf("%zu\n", sizeof(int)); printf("%zu\n", sizeof(char)); printf("%zu\n", sizeof(struct X));}

4116

with -fpack-struct option4110

Page 33: Understand more about C

33

Example of sizeof

• What about this code snippet?

#include <stdio.h>struct X { int a; char b; int c; char *d; };

int main(void){ printf("%zu\n", sizeof(int)); printf("%zu\n", sizeof(char)); printf("%zu\n", sizeof(struct X));}

4124

with -fpack-struct option4117

Suppose the program is on a 64-bit machine running in 64-bit mode

c

b

a

d

24

16

12

8

4

0

Page 34: Understand more about C

34

ALIGNMENT

Page 35: Understand more about C

35

Alignment issue

The legacy code snip is working well in X86 CISC machine where instructions are available to directly access unaligned data in memory.

When porting this legacy code from a CISC architecture to ARM RISC machine, it will have some issues.

• The most common unaligned access code

#include <stdio.h>struct X { int a; char b; int c; char *d;} __attribute((packed));

int main(void) { struct X ss; ss.c = 10; return ss.c;}

http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0472h/BABFDBCJ.html

Page 36: Understand more about C

36

Alignment issue

The ARM compiler generates assembly language code that reads the word using an LDR instruction.

If the address is not a multiple of four, the LDR instruction returns a rotated result rather than performing a true unaligned word load.

#include <stdio.h>struct X { int a; char b; int c; char *d;} __attribute((packed));

int main(void) { struct X ss; ss.c = 10; return ss.c;}

0 1 2 3 4 5 6 7 8

Generally, this rotation is not what the programmer expects.

• The most common unaligned access code

Page 37: Understand more about C

37

Alignment issue

X86 asm:.loc 1 11 0 movl $10, -27(%rbp).loc 1 12 0 movl -27(%rbp), %eax

ARMv5 asm:.loc 1 11 0 ldr r3, [fp, #-16] and r3, r3, #255 orr r3, r3, #2560 str r3, [fp, #-16] mov r3, #0 strb r3, [fp, #-12].loc 1 12 0 ldr r3, [fp, #-16] mov r3, r3, lsr #8 ldrb r2, [fp, #-12] @ zero_extendqisi2 mov r2, r2, asl #24 orr r3, r2, r3 mov r0, r3

#include <stdio.h>struct X { int a; char b; int c; char *d;} __attribute((packed));

int main(void) { struct X ss; ss.c = 10; return ss.c;}

b

a

d

161514131211109876543210

c

• The most common unaligned access code

Page 38: Understand more about C

38

Alignment issue

ARMv7 asm:.loc 1 11 0 ldr r3, [fp, #-16] uxtb r3, r3 orr r3, r3, #2560 str r3, [fp, #-16] mov r3, #0 strb r3, [fp, #-12].loc 1 12 0 ldr r3, [fp, #-15] @ unaligned mov r0, r3

ARMv5 asm:.loc 1 11 0 ldr r3, [fp, #-16] and r3, r3, #255 orr r3, r3, #2560 str r3, [fp, #-16] mov r3, #0 strb r3, [fp, #-12].loc 1 12 0 ldr r3, [fp, #-16] mov r3, r3, lsr #8 ldrb r2, [fp, #-12] @ zero_extendqisi2 mov r2, r2, asl #24 orr r3, r2, r3 mov r0, r3

#include <stdio.h>struct X { int a; char b; int c; char *d;} __attribute((packed));

int main(void) { struct X ss; ss.c = 10; return ss.c;}

On ARMv6 and later architectures, unaligned access is fully supported.

-munaligned-access-mno-unaligned-accessEnables (or disables) reading and writing of 16- and 32- bit values from addresses that are not 16- or 32- bit aligned. By default unaligned access is disabled for all pre-ARMv6 and all ARMv6-M architectures, and enabled for all other architectures.https://gcc.gnu.org/onlinedocs/gcc/ARM-Options.html

b

a

d

161514131211109876543210

c

• The most common unaligned access code

Page 39: Understand more about C

39

Alignment issue

#include <stdio.h>struct X { int a; char b; int c; char *d;} __attribute((packed));

int main(void) { struct X ss; ss.c = 10; return ss.c;}

http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0333h/Cdfcgggi.html

• A==1:• unaligned access causes an Alignment fault Data Abort

exception• U==0 and A==0:

• if unaligned access, the LDR instruction returns a rotated result rather than performing a true unaligned word load

• U==1 and A==0:• unaligned access support for loads and stores of single 16-bit

half-words and 32-bit words

Table L-1 SCTLR.U bit values for different architecture versions in ARM architecture reference manual

• The most common unaligned access code

Page 40: Understand more about C

40

INLINE FUNCTION

Page 41: Understand more about C

41

Inline function

• gcc inlinea.c inlineb.c– inlineb.c: multiple definition of 'max'

• gcc inlinea.c inlineb.c -O1– inlineb.c: multiple definition of 'max'

• gcc inlinea.c inlineb.c -std=c99– inlinea.c: undefined reference to 'max' – inlineb.c: undefined reference to 'max'

• gcc inlinea.c inlineb.c -std=c99 -O1– compiled successfully

/* inline.h header file */inline int max(int a, int b) { return a > b ? a : b;}

/* inlinea.c source file */#include "inline.h“extern int foo(int a, int b);

int main(void) { int a; a = foo(10,20); a = max(a,30); return a;}

/* inlineb.c source file */#include "inline.h“

int foo(int a, int b) { int c; c = max(a,b); return c;}

Page 42: Understand more about C

42

Inline function

• gcc inlinea.c inlineb.c– inlinea.c: undefined reference to 'max' – inlineb.c: undefined reference to 'max'

• gcc inlinea.c inlineb.c -O1– compiled successfully

• gcc inlinea.c inlineb.c -std=c99– inlineb.c: multiple definition of 'max'

• gcc inlinea.c inlineb.c -std=c99 -O1– inlineb.c: multiple definition of 'max'

/* inline.h header file */extern inline int max(int a, int b) { return a > b ? a : b;}

/* inlinea.c source file */#include "inline.h“extern int foo(int a, int b);

int main(void) { int a; a = foo(10,20); a = max(a,30); return a;}

/* inlineb.c source file */#include "inline.h“

int foo(int a, int b) { int c; c = max(a,b); return c;}

Page 43: Understand more about C

43

Inline function

• static inline– The definition is equal in GNU89 and C99.– The function will be used in the same translation units. If the function is inlined, the

stand-alone object code is never emitted.– If the function is not inlined, the stand-alone object code will be emitted, but it can

not be used by other translation units.

• Inline– In GNU89, no matter the function is inlined, the stand-alone object code will be

emitted, and can be used by other translation units.– In C99, no matter the function is inlined, the stand-alone object code will not be

emitted.

• extern inline– In GNU89, no matter the function is inlined, the stand-alone object code will not be

emitted.– In C99, no matter the function is inlined, the stand-alone object code will be

emitted, and can be used by other translation units.

Page 44: Understand more about C

44

Inline function – Portable model

• gcc inlinea.c inlineb.c– compiled successfully

• gcc inlinea.c inlineb.c -std=c99– compiled successfully

• gcc inlinea.c inlineb.c -O1– compiled successfully

• gcc inlinea.c inlineb.c -std=c99 -O1– compiled successfully

/* inline.h header file */static inline int max(int a, int b) { return a > b ? a : b;}

/* inlinea.c source file */#include "inline.h"extern int foo(int a, int b);

int main(void) { int a; a = foo(10,20); a = max(a,30); return a;}

/* inlineb.c source file */#include "inline.h"

int foo(int a, int b) { int c; c = max(a,b); return c;}

inlinea.o: U foo T main t max

inlineb.o: T foo t max

inlinea.o: U foo T main

inlineb.o: T foo

Page 45: Understand more about C

45

Inline function –GNU89 model

• gcc inlinea.c inlineb.c– compiled successfully

• gcc inlinea.c inlineb.c -O1– compiled successfully

/* inline.h header file */extern inline int max(int a, int b) { return a > b ? a : b;}

/* inlinea.c source file */#include "inline.h"extern int foo(int a, int b);

int main(void) { int a; a = foo(10,20); a = max(a,30); return a;}

/* inlineb.c source file */#include "inline.h"int max(int a, int b);

int foo(int a, int b) { int c; c = max(a,b); return c;}

inlinea.o: U foo T main

inlinea.o: U foo T main U max

inlineb.o: T foo T max

inlineb.o: T foo T max

Page 46: Understand more about C

46

Inline function –C99 model

• gcc inlinea.c inlineb.c -std=c99– compiled successfully

• gcc inlinea.c inlineb.c -std=c99 -O1– compiled successfully

/* inline.h header file */inline int max(int a, int b) { return a > b ? a : b;}

/* inlinea.c source file */#include "inline.h"extern int foo(int a, int b);

int main(void) { int a; a = foo(10,20); a = max(a,30); return a;}

/* inlineb.c source file */#include "inline.h"extern int max(int a, int b);

int foo(int a, int b) { int c; c = max(a,b); return c;}

inlinea.o: U foo T main U max

inlinea.o: U foo T main

inlineb.o: T foo T max

inlineb.o: T foo T max

References:http://www.greenend.org.uk/rjk/tech/inline.htmlhttps://gustedt.wordpress.com/2010/11/29/myth-and-reality-about-inline-in-c99/http://www.drdobbs.com/the-new-c-inline-functions/184401540https://gcc.gnu.org/onlinedocs/gcc/Inline.html

Page 47: Understand more about C

47

ADD-ON

Page 48: Understand more about C

48

Volatile type qualifier

• Two functions each executed in a separate thread with the same pointer as a parameter

void add( int *i) { while (1) { *i = 0; for (int a=0; a<10; a++) (*i)++; }}

void check( int *i) { while (*i != 5) ;}

void add(volatile int *i) { while (1) { *i = 0; for (int a=0; a<10; a++) (*i)++; }}

void check( int *i) { while (*i != 5) ;}

C99 support

Referenceshttps://en.wikipedia.org/wiki/Volatile_%28computer_programming%29https://gcc.gnu.org/onlinedocs/gcc/Volatiles.html

Page 49: Understand more about C

49

Variable length argument

• http://blog.aaronballman.com/2012/06/how-variable-argument-lists-work-in-c/

#include <stdarg.h>void foo( int bar, ... ){ va_list args; va_start( args, bar );

for (;;) { some_type t = va_arg( args, some_type ); /* Do something with t */ } va_end( args );}

Page 50: Understand more about C

50

Nested function

#include <stdio.h>typedef int (*func_t)(int);static func_t foo(int arg){ int nested(int nested_arg) { return (arg + nested_arg); } return &nested;}int main(){ func_t g = foo(100); printf("%d\n", (*g)(20)); return 0;}

nested: access foo frame by ip register mov r0, #result bx lr

foo: load .LTRAMP0 into stack store the @frame to TRAMP0[2] store the @nested to TRAMP0[3] flush cache mov r0, @TRAMP0 bx lr

main: bl foo blx r0 bl printf bx lr

.word TRAMP0

.word nested

TRAMP0: ldr ip, [pc, #0] ldr pc, [pc, #0] .word 0 .word 0 trampoline

Referenceshttps://gcc.gnu.org/onlinedocs/gcc/Nested-Functions.htmlhttps://gcc.gnu.org/onlinedocs/gccint/Trampolines.htmlhttp://blog.linux.org.tw/~jserv/archives/2010/07/gcc_nested_func.html

Page 51: Understand more about C

51

Arrays of length zero

• Arrays of Length Zero

#include <stdio.h>struct X { int a; char b; int c; char d[0];};

int main(void) { printf("%zu\n", sizeof(struct X)); return 0;}

#include <stdio.h>struct X { int a; char b; int c; char d[];};

int main(void) { printf("%zu\n", sizeof(struct X)); return 0;}

A real case in linux kernel: http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/include/uapi/linux/romfs_fs.h

C99: flexible array memberGNU C supportC90 should have length 1

C99: array of a variable sized[length], length is runtime define

https://gcc.gnu.org/onlinedocs/gcc/Variable-Length.html

Page 52: Understand more about C

52

Restricted pointers (C99)

• What is the issue of the following code?

• Solution:

void copy( char *s1, char *s2, int n){ while (n--) *s1++ = *s2++;}

void copy ( char restrict *s1, char restrict *s2, int n){ while (n--) *s1++ = *s2++;}

Page 53: Understand more about C

53

APPENDIX

Page 54: Understand more about C

54

More about new standard

• C99– https://en.wikipedia.org/wiki/C99

• C11– https://en.wikipedia.org/wiki/C11_%28C_standard_revision%29– http://blog.smartbear.com/codereviewer/c11-a-new-c-standard-ai

ming-at-safer-programming/