Understand more about C

Post on 14-Apr-2017

187 views 0 download

Transcript of Understand more about C

Understand more about C

2016

issue.hsu@gmail.com

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.

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.

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.

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.

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

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

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();

}

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();

}

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();

}

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();

}

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();

}

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();

}

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

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();}

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);}

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);

18

SEQUENCE POINT

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

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.

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.

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.

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

24

POINTERS

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;}

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

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)

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

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

30

SIZEOF

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

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

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

34

ALIGNMENT

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

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

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

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

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

40

INLINE FUNCTION

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;}

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;}

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.

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

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

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

47

ADD-ON

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

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 );}

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

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

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++;}

53

APPENDIX

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/