Beginning C for Java Programmers --------------------------------- - - PowerPoint PPT Presentation

beginning c for java programmers c syntax c started in
SMART_READER_LITE
LIVE PREVIEW

Beginning C for Java Programmers --------------------------------- - - PowerPoint PPT Presentation

cnotes.txt Tue Mar 28 15:19:23 2017 1 cnotes.txt Tue Mar 28 15:19:23 2017 2 Beginning C for Java Programmers --------------------------------- C Syntax C started in the early 1970s as a systems-programming --------- language. Much C


slide-1
SLIDE 1

cnotes.txt Tue Mar 28 15:19:23 2017 1

Beginning C for Java Programmers

  • C started in the early 1970s as a systems-programming

language. Higher level than assembly language. Lower level than most other languages. K & R : Kernighan and Ritchie Influential 1978 book Greatly tamed in 1989: ANSI C "C89" or "C90" Also revised 1999 and 2011.

cnotes.txt Tue Mar 28 15:19:23 2017 2

C Syntax

  • Much C syntax was borrowed by Java.

Same control structures as Java. C99 allows declaring variable in for loop and anywhere in code. (Like Java) ANSI C requires that local vars be declared before any statements in any {.....} block. Array syntax is not as "logical" as Java’s

slide-2
SLIDE 2

cnotes.txt Tue Mar 28 15:19:23 2017 3

The Preprocessor

  • Unlike Java, the C compiler has a "preprocessor"

that does textual substitutions and "conditional compilation" before the "real compiler" runs. This was borrowed from assembly languages. Fancy uses of preprocessor are often deprecated, especially since C99. Still commonly used use for defining constants and in doing the C equivalent to Java’s "import". Preprocessor "directives" start with #. No ’;’ at end

cnotes.txt Tue Mar 28 15:19:23 2017 4

Macros in the C Preprocessor

  • #define FOO 12*2

thereafter, wherever the symbol FOO occurs in your code, it is textually replaced by 12*2 . Think find-and-replace. Macro can have parameters #define BAR(x) 12*x If we have BAR(3*z) in your code, it is textually replaced by 12*3*z #undef BAR will "undefine" BAR. After this, BAR(3*z) remains as is.

slide-3
SLIDE 3

cnotes.txt Tue Mar 28 15:19:23 2017 5

Perils of Macros

  • #define SQUARE(x) ((x)*(x))

used much later with int x = 0; int y = SQUARE(x++); What value for x is expected by a programmer looking only at these lines? What value does x actually have?

cnotes.txt Tue Mar 28 15:19:23 2017 6

Making Strings and Concatenating Tokens

  • (optional fancy topic)

In a macro definition, the # operator puts quote marks around a macro argument. #define STRINGIFYME(x) # x STRINGIFYME(owen) expands to "owen" The ## operator joins two tokens together. #define DECL_FUNC(name) int name ## _xy (int z){\ return(3 + name);} then DECL_FUNC(owen) ends up defining a function called owen_xy that returns 3 + owen

slide-4
SLIDE 4

cnotes.txt Tue Mar 28 15:19:23 2017 7

Predefined Macros

  • __FILE__ and __LINE__ expand to the current src

code file name and line number. Good for auto-generated warning messages etc. __func__ name of current function (C99)

cnotes.txt Tue Mar 28 15:19:23 2017 8

Conditional Compilation in C

  • #if ZZ == 1 #ifdef FOO

...somecode1... ..... #else #else ...somecode2... ..... #endif #endif also #ifndef Check a Boolean condition that can be evaluated at compile time, or chk definedness ** Determines whether somecode1 or somecode2 is seen by the real compiler Only one of the 2 sequences is used **

slide-5
SLIDE 5

cnotes.txt Tue Mar 28 15:19:23 2017 9

Conditional Compilation part II

  • Conditional compilation is often used to tailor

the code for a particular models of computer. And to ensure that a given "include file" isn’t seen too many times (more later)

cnotes.txt Tue Mar 28 15:19:23 2017 10

#include statement

  • #include "foo.h" will cause the contents of your

file foo.h to be inserted in place of the #include statement. "copy paste the file here, please" #include is usually used like "import" in Java. It makes available library things. Most C programs have a line #include <stdio.h> since you can’t print otherwise. (note angle brackets for system libraries)

slide-6
SLIDE 6

cnotes.txt Tue Mar 28 15:19:23 2017 11

Simple C program

  • #include <stdio.h>

#define N 5 int g; // C99-style comment: program needs a main() int main(void) { int i; g = N; for (i=0; i < g; ++i) printf("Hello world"); }

cnotes.txt Tue Mar 28 15:19:23 2017 12

Common C Programming Conventions

  • Whereas camelCase is the standard in Java, in C the

tradition is to use underscores_to_separate the various parts of a compound identifier. UPPER CASE is conventionally used for preprocessor macros used as constants and some macros with arguments (but other macros-with-arguments get written in lower case, pretending to be functions)

slide-7
SLIDE 7

cnotes.txt Tue Mar 28 15:19:23 2017 13

Enums

  • As in Java, C89 provides enumerated types

enum studentkind {Undergrad, Grad}; enum studentkind sk = Undergrad;

cnotes.txt Tue Mar 28 15:19:23 2017 14

C has no objects

  • Methods are called "functions".

Equivalent to Java static methods. A program consists of a bunch of functions, segmented into multiple source code files (sometimes called "modules"). Need main(). C allows you to group related data together (just like a class does). Called a "struct". More later. If you want C with objects, you want C++ (or Objective C)

slide-8
SLIDE 8

cnotes.txt Tue Mar 28 15:19:23 2017 15

Order of declaration matters

  • A function cannot be called before (in

source-code order) it has been declared. It can be declared and defined by giving its code (like giving code for a static method). Or it can just be declared by giving its parameters and return type. Called a "function prototype". A full definition must then be given afterward

cnotes.txt Tue Mar 28 15:19:23 2017 16

Example

  • /* doubleslashed comments only with C99 */

int foo(int a); /* function prototype */ double bar(int x, int y) { /* defined */ return foo( 2*x*y); /* uses foo */ } .... int foo(int a) { int x; if (a==0) return bar(a,a); else return 27; }

slide-9
SLIDE 9

cnotes.txt Tue Mar 28 15:19:23 2017 17

Library header files

  • One of the main things contained in library

header files (eg, <stdio.h>) are the function prototypes for the routines that the library makes available. (Often also some constant declarations and data type (struct) definitions) So <stdio.h> contains prototypes for printf scanf various file I/O routines

cnotes.txt Tue Mar 28 15:19:23 2017 18

Void parameter list

  • A function with no parameters uses void in its

parameter list. int foobar(void) {.....} vs Java’s int foobar() {....}

slide-10
SLIDE 10

cnotes.txt Tue Mar 28 15:19:23 2017 19

Order of Parameter Evaluation

  • For functions with multiple parameters, it is

undefined in which order the parameters are evaluated. { int i=0; foo(i++,i++); } you may have called foo(0,1) or foo(1,0). Do not rely on any particular behaviour.

cnotes.txt Tue Mar 28 15:19:23 2017 20

Static Functions and Extern Variables

  • If you use the qualifier "static" when defining

a function, it will not be exported for linking, which is the default. Keyword extern is used when a variable is being imported from another module. One of the modules needs extern int v; int v; to define the value and pass to the linker. Or use extern int v=23;

slide-11
SLIDE 11

cnotes.txt Tue Mar 28 15:19:23 2017 21

Stack Frames

  • Compilers generate stack frames according to the

approved calling conventions for that system. Look at the Resources section: ARM Stack Frame Layout (Windows CE 5.0). More later about "alloca()". Appears consistent with AAPCS. Note the "Frame Pointer". Some calling conventions use frame pointers (aka BP); others don’t. This one requires FP in only some cases.

cnotes.txt Tue Mar 28 15:19:23 2017 22

Widening and Narrowing Rules

  • Widening: conversion of a datatype to one that that

can handle all the original values (and maybe more) (eg, short to int) Narrowing: conversion to a more restricted datatype. Risk a value won’t be representable anymore. In Java, you need explicit typecasts more often than you do in C. int i = 3.14; //narrowing, Java needs typecast float f = 3; // widening, Java is also ok with this my_arg_should_be_float(3.14); // narrowing, Java cast

slide-12
SLIDE 12

cnotes.txt Tue Mar 28 15:19:23 2017 23

Promotion

  • If i is an int and l is a long,

i*l is same as (long)i * l (same as Java) What if i is an int and u is an unsigned int. What is i*u? Ans: same as (unsigned int)i * u No such issue in Java, since no unsigned... How about if c is a signed character and u is an unsigned int? c*u is same as ( (unsigned int) ( (int) c))* u

  • --> assuming 2’s complement, using sign extension

cnotes.txt Tue Mar 28 15:19:23 2017 24

Simple IO in C

  • printf for screen output (note: Java now has printf!)

also putchar scanf and getchar for keyboard input printf takes first a "format string", then a variable # of things eg printf("Hello world!"); printf("value of x=%d, and y=%s", x, my_str); scanf uses a format string too scanf("%d %d %d", &x, &y, &z); Note use of "address-of" operator & Reason will be explained later.

slide-13
SLIDE 13

cnotes.txt Tue Mar 28 15:19:23 2017 25

Getchar and the EOF bug

  • Function getchar() returns a character from the

standard input stream (normally, the keyboard). If there are no more characters (standard input has closed), it returns the value EOF. getchar() actually returns an int. EOF is usually

  • 1.

If getchar’s output has been typecast to char, it will never be equal to EOF. So getchar() into an int. After checking for EOF, then typecast (or assign) to a char.

cnotes.txt Tue Mar 28 15:19:23 2017 26

I/O Buffering

  • On many systems, input is buffered: nothing happens

until a newline is hit. (Until then you can edit your keyboard input). And many systems buffer output: nothing actually gets sent to the screen (or to a file) until a newline is sent, or more than some number of kb

  • f data is ready to send.

Buffered I/O is good for system efficiency but hard

  • n programer heads.
slide-14
SLIDE 14

cnotes.txt Tue Mar 28 15:19:23 2017 27

Data Types

  • Basic types are sorta similar to Java:

int, double, float, long, short, char integer types can be qualified with "unsigned". int A[57]; vs Java int [] A = new int[57]; Before C99, the array size must be known at compile time. Before C99, no boolean type. Now there is bool, if you #include <stdbool.h>.

cnotes.txt Tue Mar 28 15:19:23 2017 28

Important Difference with Java

  • C was originally envisioned as a platform dependent

language. So an int means different things on different

  • platforms. (Is it 16 bits? 32 bits? 64 bits?)

C can be used on systems that don’t use 2’s complement short must be able to represent -32767 to 32767. int must be able to represent -32767 to 32767. long: -2147483647 to 2147483647 But ranges can be larger. However, range of short cannot exceed range of int, which cannot exceed range of long.

slide-15
SLIDE 15

cnotes.txt Tue Mar 28 15:19:23 2017 29

Fixed-Width Integer Types

  • It’s hard to do some low-level programming without

knowing bit width. So C99 adds header file <stdint.h> Defines data types like int32_t, uint64_t etc. int32_t is guaranteed to give 32 bits range There are macros to declare constants of these types. Eg, UINT64_C(12345)

cnotes.txt Tue Mar 28 15:19:23 2017 30

Variable scope

  • global variables

are like object variables. Except the whole program is essentially one object... visible to all functions in the source code where declared. local variable same as Java .... except that you can qualify with "static", same scope, but now allocated as with the globals. Slightly tamed global variable, sometimes useful. it is okay to use an uninitialized local: your problem if the garbage chokes you.

slide-16
SLIDE 16

cnotes.txt Tue Mar 28 15:19:23 2017 31

Strings

  • In C, strings are just null-terminated char arrays.

Just like in assembly language. Libraries have many convenient string functions. Join strings with strncat. No "+" operator, sadly. Hint: Linux command man 3 strncat tells you all about the strcat function, which is in section 3 (C library) of manuals.

cnotes.txt Tue Mar 28 15:19:23 2017 32

Const

  • Types can be qualified with const.

Similar to some uses of "final" in Java. This indicates things whose values cannot be changed (after initialization). eg const int months_per_year = 12; Using these effectively can be annoying, as the compiler may force you to do a lot of typecasting when you insert one or two uses.

slide-17
SLIDE 17

cnotes.txt Tue Mar 28 15:19:23 2017 33

Volatile

  • Types can also be qualified with volatile.

(Same keyword with similar meaning exists in Java but is not widely used) Volatile means that the compiler cannot assume that the value won’t change, mysteriously. (eg, value coming from a hardware device or value that another thread could be messing with) volatile int v; .... while (v) {...something...} is NOT equivalent to if (v) while (true) {....something...}

cnotes.txt Tue Mar 28 15:19:23 2017 34

The Harder Parts of C

  • * Pointers. Lower level access to memory than Java

Chapter from K&R in D2L. Read carefully. * Memory Management. Lower level. Read wikibook section. * How nontrivial programs are segmented into modules Read my notes on the website

slide-18
SLIDE 18

cnotes.txt Tue Mar 28 15:19:23 2017 35

Pointers

  • A C pointer is a slightly higher level view of a

memory address than an assembler programmer would have. A C pointer has a memory address, but the compiler also knows the type of the thing that is in memory at that address. More importantly, the compiler knows how many memory addresses are taken up by each type. Aside: you can find this out with sizeof operator.

cnotes.txt Tue Mar 28 15:19:23 2017 36

Pointers vs Java’s Object References

  • In Java, an object reference is very much

like a pointer, except you are very limited in what you can do with it.

slide-19
SLIDE 19

cnotes.txt Tue Mar 28 15:19:23 2017 37

C Pointers

  • Pointer values can be

* stored in variables * passed in parameters * involved in weird pointer expressions * incremented * dereferenced Dereferencing means getting the value that is in the pointed-to memory address. It is "following the pointer"

cnotes.txt Tue Mar 28 15:19:23 2017 38

The * operator

  • You dereference a pointer using the unary *
  • perator.
slide-20
SLIDE 20

cnotes.txt Tue Mar 28 15:19:23 2017 39

Declaring a Pointer Variable

  • int *foo; <-- declares a pointer to an int

float *bar; <-- bar points to a float int **baz <-- variable baz stores a pointer to a memory location that itself contains a pointer (to an int) Picture on board is needed.

cnotes.txt Tue Mar 28 15:19:23 2017 40

Const and Pointer Declarations

  • const int *p; <-- p cannot be used to change the

pointee p can be reassigned to point to

  • ther constant integers

int * const q; <-- q points to an integer q can be used to alter the pointee q cannot be reassigned. const int * const r <-- r points to an integer r cannot be reassigned, nor can r be used to change pointee

slide-21
SLIDE 21

cnotes.txt Tue Mar 28 15:19:23 2017 41

Const pointers and typecasting

  • void foo( int *p) {...do stuff with p...}

int bar( const int *q){... foo(q);... } You get an error or warning about implicitly stripping the const-ness from q when handing it to foo. You _should_ make int foo (const int *p) if foo can guarantee this

  • r

int bar (int *q) if foo cannot.

  • r do explicit cast foo( (int *) q) to shut up

compiler but get officially undefined behaviour.

cnotes.txt Tue Mar 28 15:19:23 2017 42

Address-of Operator

  • Given a variable, you can get a pointer to it

using unary & operator, which we sometimes call the "address of" operator. int x = 5; int *y = &x; (*y++)++; int *z; z = y; /* pointer assignment */ (Actually & can be applied to any expression that yields an "lvalue". An lvalue is something that, except for possible "constant-ness" restrictions, could be assigned to. More or less.)

slide-22
SLIDE 22

cnotes.txt Tue Mar 28 15:19:23 2017 43

Operator Precedences

  • The * and & operators have fairly high precedence.

So *x+3 means (*x) + 3, not *(x+3). But watch out, because ++ has equal precedence. So you must write (*x)++ instead of *x++ because both * and ++ are right associative.

cnotes.txt Tue Mar 28 15:19:23 2017 44

Pointers as Parameters

  • void swap(int *x, int *y) {

int temp = *x; *x = *y; *y = temp; } int a=5, b=6; swap(&a, &b); vs the simpler but broken void swap(int x, int y) { int temp = x; x=y; y=temp; } swap(a,b);

slide-23
SLIDE 23

cnotes.txt Tue Mar 28 15:19:23 2017 45

Simulating Output Parameters

  • Some languages let a method communicate back

to its caller by changing the parameters. Not Java, and not C. But in C, you can simulate this via pointers. The swap routine did this. Handy when you want a method to "return several values".

cnotes.txt Tue Mar 28 15:19:23 2017 46

Generic Pointers

  • Sometimes you need a pointer for which the

type of the pointed-to information is unknown

  • r temporarily irrelevant.

C provides the "void pointer" for this. You cannot do much with a void pointer - eg, you cannot dereference it. You can typecast a void pointer to any other pointer type, though. void *foobar;

slide-24
SLIDE 24

cnotes.txt Tue Mar 28 15:19:23 2017 47

Malloc

  • Pointers can be to blocks of memory in

* the stack * the global uninitialized area * the global initialized area * the "heap" The runtime heap corresponds to the pool of memory Java uses when you use the "new" operator. In C, you can ask for a block of heap memory using the malloc() library function. Argument is the number of bytes you want. Result returned as a (void *) that you can typecast to the desired ptr type. Any memory taken with malloc() should eventually be returned with free(). C has no GC.

cnotes.txt Tue Mar 28 15:19:23 2017 48

Pointer Fun with Binky

  • Let’s look at a classic claymation video on C
  • pointers. (Good for your inner 11-year-old.)
slide-25
SLIDE 25

cnotes.txt Tue Mar 28 15:19:23 2017 49

More on the Heap

  • The heap is a region of memory, where chunks of this

memory get handed out on demand. Demand for C: malloc(). For Java: "new". Later, some of these chunks may become reuseable, because a C programmer called free(). The heap starts out at some size. But eventually a malloc() may find there is no free block that is big enough. Maybe all memory is in use. Maybe not, but only small blocks are available. When this happens, the heap needs to grow. It expands dynamically as needed.

cnotes.txt Tue Mar 28 15:19:23 2017 50

Memory Layout

  • So we have the stack, which occupies no set amount
  • f space. It grows and shrinks dynamically.

And we now have the heap, which also grows (and maybe shrinks) dynamically. The processor has a limited number of memory

  • addresses. We’d like to be able to support almost

all addresses for the stack (highly recursive pgm) or almost all addresses for the heap (malloc-intensive). Classic approach: Stack starts at a very high address and grows down; heap starts at a small address and grows up. As long as the top of the stack doesn’t move into the heap area, we are okay.

slide-26
SLIDE 26

cnotes.txt Tue Mar 28 15:19:23 2017 51

Other Memory Areas

  • Other possible regions of memory are for

* your machine code * your global initialized variables * your global uninitialized variables * constants [Draw picture on board] Machine-code and constants can be in read-only

  • r flash memory, whereas global variables,

stack and heap need to be in RAM. Constants can be a part of the global initialized region, or (as with our ARM examples) in with the machine code. Many calling conventions (dunno about AAPCS) dedicate registers to point at the bases of the global variable or constants regions. Facilitate use of the CPU’s pre- or post-indexed addressing mode

cnotes.txt Tue Mar 28 15:19:23 2017 52

Putting Code into RAM

  • Although a single-purpose controller can have its

program in ROM or flash memory, if you want to have an OS load various apps or programs on demand, you will need for all memory areas to be in RAM. Putting code into RAM enables a historical horror called self-modifying code. The program can

  • verwrite some of its own machine code while it is
  • running. Commonly write NOP (no-op) instructions
  • n top of things you want to disable. Or, write

BL instructions into strategically placed NOPs in the code.

slide-27
SLIDE 27

cnotes.txt Tue Mar 28 15:19:23 2017 53

Evils of Self-Modifying Code

  • + Every software engineering principle known to man

is probably violated. You cannot easily tell what the code is going to do by inspecting the source code - what happens at runtime is determined by earlier stuff that happened at runtime. + Hardware designers can boost performance if they can assume that the machine codes are unchanging at the time the program starts running. (In 3813, you might see that this kind of assumption can simplify the "instruction cache" design.)

cnotes.txt Tue Mar 28 15:19:23 2017 54

Typedef

  • Declaring C types can be tricky.

Nice to know about typedef keyword, which lets you declare an alias for any type. Put the keyword in front of what would otherwise be a variable declaration of a given type. And your "variable" is now a new type name. eg typedef int *my_int_ptr; my_int_ptr pi; my_int_ptr *ppi; <-- pointer to ptr to integer Typedef makes an alias, so there is no error if you do int *foo = pi; <-- foo and pi are both (int *)

slide-28
SLIDE 28

cnotes.txt Tue Mar 28 15:19:23 2017 55

Arrays in C

  • int A[20], B[20][30]; <-- declare a 1D and 2D array

1D case is similar to Java int [] A = new int[20]; However, with C if the declaration is outside of any function (or is in a function, but prefixed with "static"), the bytes are allocated in the same memory region as other uninitialized global variables (which will be set to 0, same as Java). A non-static array as a local variable takes up space in the activation record. Different from Java. If uninitialized, its value is weird junk, unlike Java.

cnotes.txt Tue Mar 28 15:19:23 2017 56

Bounds checking

  • In Java, all array accesses are checked to see

whether there is a bounds error. Not the case in C, where you will read junk and write corruption... C11 may help with this.

slide-29
SLIDE 29

cnotes.txt Tue Mar 28 15:19:23 2017 57

Array Initializers

  • Similar to Java, C arrays can be initialized

int a[] = {3,1,4,1,5}; char *names[] = {"bob","penny","yulin"}; int b[2][2]={ {1,2},{3,4} }; If a global, it will be stored in a memory region with

  • ther initialized globals (different region than the

uninitialized globals).

cnotes.txt Tue Mar 28 15:19:23 2017 58

Pointers and Arrays

  • Pointers and arrays - very closely related in C.

int A[10]; <-- similar to Java int [] A = new int[10]; int *pa = A; <-- allowed A = pa; <-- not allowed, array name is constant *pa = 5; <-- same as A[0] = 5 *(pa+i) is same as A[i] or pa[i]

slide-30
SLIDE 30

cnotes.txt Tue Mar 28 15:19:23 2017 59

Pointer Arithmetic

  • To make it so that *(pa+i) means same as pa[i],

we need that pa+i points to the address of the ith element of the array. If each array element

  • ccupies k bytes, we need the memory address of

(pa+i) to be i*k bytes after the address of pa. So: What does while ( *p++){} do? If pa and pb are pointers to different parts of the same array, you are allowed to subtract them. Result is the number of array elements between them.

cnotes.txt Tue Mar 28 15:19:23 2017 60

Pointer Comparisons

  • If p and q point to elements of the same array

(or fields of the same object), then it is allowed to compare them for ==, !=, >, >= etc. The integer 0 is used as NULL in C. In earlier versions C, pointers are integers were somewhat interchangeable. Not any more. However, 0 is special. It is okay to do a pointer comparison between a pointer within an array and a pointer that is ONE past the end of an array. 0 (as a pointer or integer) is equivalent to false in C. Hence if ( p && *p == ’a’) .....

  • r if ( p != 0 && *p == ’a’)....
slide-31
SLIDE 31

cnotes.txt Tue Mar 28 15:19:23 2017 61

String Copy

  • void strcpy( char *s, const char *t) {

while (*s++ = *t++) ; } vs void strcpy(char *s, const char *t) { int i = 0; while (s[i] = t[i]) i++; }

cnotes.txt Tue Mar 28 15:19:23 2017 62

Malloc, Calloc, Realloc and Free

  • Malloc allocates (uninitialized) memory on the heap.

So does calloc(n,s) where n is the number of items and s is the size of each. All bytes zeroed. realloc(p, s) attempts to enlarge the malloc’ed area at p to size s. If this can’t be done, it mallocs a new area of size s and copies the data at p over to it. Returns a pointer, regardless free(p) releases the previously allocated memory. It can then be reused. Forget to release: "memory leak" Release twice: heap corruption.

slide-32
SLIDE 32

cnotes.txt Tue Mar 28 15:19:23 2017 63

Valgrind and GCC options

  • Manual memory management is the source of much

efficiency and many tears. Software tools exist that check for memory leaks, heap corruption and other common errors. One is "valgrind". Within the last year or two, the GNU C compiler suite has added options that let you check for similar corruption and also use of uninitialized values.

  • Wuninitialized -Wmaybe-uninitialized
  • fsanitize variations such as -fsanitize=address
  • r -fsanitize=undefined

cnotes.txt Tue Mar 28 15:19:23 2017 64

Alloca

  • The alloca(s) function is like malloc() except

that it generates space in the stack frame. Can be more efficient, but its use is discouraged. Space created with alloca is automatically recovered when the function returns. DO NOT CALL FREE on space gotten with alloca

slide-33
SLIDE 33

cnotes.txt Tue Mar 28 15:19:23 2017 65

Function Pointers

  • Some of the neat things that object-oriented folks

are used to doing - you can accomplish them in C using "function pointers". A function pointer is essentially the starting memory address of a piece of code. The compiler knows the type of the function (its return type and the number and type of its parameters). Sample declaration: int foo(float bar){........} int goo(float baz){........} int (*fptr)(float); fptr = foo; (*fptr)(3.14);

cnotes.txt Tue Mar 28 15:19:23 2017 66

Example: Library Quicksort

  • Generic comparison-based quicksort.

It should be able to take any kind of data, as long as you tell the library. Library prototype (from stdlib.h): void qsort(void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *));

  • r void qsort(void *base, size_t nmemb, size_t size,

int compar(const void *, const void *)); Use: #define N 100 double my_arr[N]; int my_compare( const void *p1, const void *p2) { double d1 = * ((double *) p1); double d2 = * ((double *) p2); if (d1 > d2) return +1; if (d2 > d1) return -1; return 0;} int main() { qsort( my_arr, N, sizeof(double), my_compare);}

slide-34
SLIDE 34

cnotes.txt Tue Mar 28 15:19:23 2017 67 cnotes.txt Tue Mar 28 15:19:23 2017 68

Alternative with Hairy Typecast

  • #include <stdlib.h>

#define N 100 double my_arr[N]; int my_compare( double *d1, double *d2) { if (*d1 > *d2) return +1; if (*d2 > *d1) return -1; return 0;} int main() { qsort( my_arr, N, sizeof(double), (int (*)(const void *, const void *) ) my_compare); }

slide-35
SLIDE 35

cnotes.txt Tue Mar 28 15:19:23 2017 69

Memcpy etc

  • A few library routines in <string.h> allow memory

copying void *memcpy(void *dest, const void *src, size_t n); copy n bytes; dest and src areas must not overlap void *memmove(void *dest, const void *src, size_t n); less efficient, but overlap is okay char *strncpy(char *dest, const char *src, size_t n); stops copy early if null byte seen. No overlap.

cnotes.txt Tue Mar 28 15:19:23 2017 70

Structs

  • Structs are like Java classes without
  • a. inheritance
  • b. methods

And all fields ("members") are public. struct point { <-- "point" is optional, but... float xcoord, ycoord; } point1, point2; point1.xcoord = 23.1; struct point point3; <-- ..this would not be possible w/o having the point tag point3.ycoord = 5.4; point2 = point1; <-- copy entire struct

slide-36
SLIDE 36

cnotes.txt Tue Mar 28 15:19:23 2017 71

Structs and Typedef

  • Repeatedly having to type the keyword "struct" when

declaring variable/parameters is tedious. Recall typedef sets up a type alias...so typedef struct { <-- didn’t use the "point" tag here float xcoord, ycoord;} point_t; point_t point1, point2, point3; <-- same as before

cnotes.txt Tue Mar 28 15:19:23 2017 72

Structs: Assignments

  • In Java, you have a references to objects. To get an

actual object, you need "new". So assignment jRef1 = jRef2 means that there is 1

  • bject, and 2 references to it.

jRef1.field = 5 changes jRef2.field. In C, struct assignment is more like basic type

  • assignment. It is "by value".

Declaring the struct variable makes "the object". point_t point1, point2; <-- 2 different structs point1 = point2; <-- still 2 different structs point1.xcoord - 4.2; <-- no change to point2.xcoord

slide-37
SLIDE 37

cnotes.txt Tue Mar 28 15:19:23 2017 73

Structs and Functions

  • point_t foo( point_t pt) { ....}

point2 = foo(point1); Passing point1 as parameter means that a bitwise assignment (copy) of point1 is put into the activation record of foo. Subsequent changes made to parameter pt have no effect on point1. When foo returns, a full assignment is done into point2. C structs as parameters and returns: handled more the way that Java handles basic types (not how Java handles object types).

cnotes.txt Tue Mar 28 15:19:23 2017 74

Pointers to Structs

  • Java object references are actually closer to a C

pointer to a struct. point_t *foo( point_t *pt) {....} point_t *pt2; pt2 = foo( &point1); Now the activation record of foo has a pointer to the same struct object that the main program called "point1" Subsequent changes made to *pt WILL change point1. When foo returns, a pointer is copied. Not the pointee.

slide-38
SLIDE 38

cnotes.txt Tue Mar 28 15:19:23 2017 75

Arrow Operator

  • Pointers to structs are very common in C.

Given point_t *pt = .... a very common operation is to dereference (ie, follow) the pointer to the pointee (a struct), then access

  • ne of the members of the struct.

... (*pt).xcoord... Parenthesis needed due to operator precedence. As a shorthand, we have the arrow operator, pt->xcoord which does the same thing, more elegantly.

cnotes.txt Tue Mar 28 15:19:23 2017 76

Linked-List-of_Ints Example

  • typedef struct nd { int data; struct nd *next } node;

node *head = NULL; <-- note capitals for (i=0; i < 10; ++i) { node *temp = (node *) malloc( sizeof node); temp->data = i; temp->next = head; head = temp; } ... do stuff with list, eg node *x; for (x=head; x != NULL; x = x->next) printf("I see %d\n", x->data); ... when finished, don’t forget to free up memory while (head != NULL) { node *temp = head->next; free(head); head = temp; }

slide-39
SLIDE 39

cnotes.txt Tue Mar 28 15:19:23 2017 77

Other Data Structures

  • For a couple of years in the 1990s, you would have

taken your intro data structures course in C [Electrical Enggs still do], and you’d see stacks, queues, BSTs, RedBlackTrees etc in C. struct BSTNode { int key; struct BSTNode *left, *right; }

cnotes.txt Tue Mar 28 15:19:23 2017 78

Incomplete/Undefined Struct types

  • You are allowed to declare the existence of a

struct BEFORE the compiler has seen the actual definition of the struct. Useful with parameters if they are pointers to structs. struct s z; int foo(struct s *zz) {} // legal! int bar(struct s zzz) {} // illegal int zs() { z.a = 1; } // move down to make legal struct s { int a, b; };

slide-40
SLIDE 40

cnotes.txt Tue Mar 28 15:19:23 2017 79

Unions

  • In a struct, the members are laid out in memory,
  • ne after another (with possible padding).

A union is basically a struct where all the members

  • verlap in their storage space.

It’s a low-level horror missing from Java. Approved use: you want to store an int or a double, but not both at the same time. struct { /* union inside a struct */ int storing_an_int; /* boolean */ union { int ival; double dval;} u; } s; s.storing_an_int = 0; s.u.dval = 3.1415;

cnotes.txt Tue Mar 28 15:19:23 2017 80

Type Punning with Unions

  • A union provides a way to refer to a glob of bits as

if several different types. Wanna peek at the bits of a float? union {float f; int i;} u; u.f = 3.141592; printf("The exponent field is %d\n", (u.i & 0x7f800000)>>23); We are relying on the compiler laying out f and i both starting at the same address (not padding one and not the other). This may not be technically safe with C89. But it is apparently safe in C99. (cf Wikipedia page on "type punning")

slide-41
SLIDE 41

cnotes.txt Tue Mar 28 15:19:23 2017 81

Type Punning with Pointers

  • Can do something similar without a union:

Take a pointer to one type. Typecast it to another pointer type. Dereference the result. Strictly speaking, the result might be "undefined", but most compilers have historically done what you want. float f = 3.141592; float *pf = &f; int *pi = (int *) pf; int i = *pi; (If ints have more stringent alignment rules on a platform than floats, you could get in trouble here.)

cnotes.txt Tue Mar 28 15:19:23 2017 82

Bit fields

  • struct {

unsigned int opcode : 6, unsigned int register1: 4, unsigned int register2: 4, unsigned int constant1: 12 } my_packed_structure; This declares opcode to be a 6-bit field that is packed with two 4-bit fields and a 12-bit field; my_packed_structure.opcode = 0b110100; my_packed_structure.register1 = 9; Whether opcode is the most- or least- significant 6 bits is system dependent, as are most aspects of bit fields. Good for very low-level un-portable code.

slide-42
SLIDE 42

cnotes.txt Tue Mar 28 15:19:23 2017 83

File IO

  • fprintf and fscanf allow writing/reading files.

Used in conjunction with fopen and fclose Use a (FILE *) parameter. FILE *f = fopen("hello.txt","w"); fprintf(f, "Hello world"); fflush(f); /* optional */ fclose(f);

cnotes.txt Tue Mar 28 15:19:23 2017 84

More File IO

  • getc is like getchar, but for an opened file.

fgets returns a line (or a max num of chars) from an opened file. C has no exceptions. Return codes widely used, with a global variable called "errno". Things that would be void in Java return an int in C. One int value means "it worked". Others tell you how it failed.

slide-43
SLIDE 43

cnotes.txt Tue Mar 28 15:19:23 2017 85

Interpreting Errno

  • A function perror looks at errno and prints an error

message to the "standard error" stream.

cnotes.txt Tue Mar 28 15:19:23 2017 86

Another EOF check

  • For an opened file, use feof() to check whether

end-of-file has been reached.

slide-44
SLIDE 44

cnotes.txt Tue Mar 28 15:19:23 2017 87

Additional Features for Low-Level Programming

  • While maybe not part of the C language definition,

major C compilers (GCC, Intel’s, CLANG, Visual C) tend to have similar support for additional features for low-level programming. * Intrinsic functions * Inline assembly Intrinsics are slightly higher level and I’d consider them more "modern". Intrinsics and inline assembly can be contrasted with just writing some subroutines in assembly, and then linking the resulting object code with object code resulting from compiling C source.

cnotes.txt Tue Mar 28 15:19:23 2017 88

Intrinsics

  • (cf Wikipedia: Intrinsic_function)

An intrinsic function is syntactically a library

  • function. However, the compiler will have some

baked-in magic when it sees this "function" used, and it will usually compile the intrinsic to a straight-line code sequence that makes use of some particular special CPU instruction. Intrinsics make available special CPU capabilities while still appearing to be library function calls.

slide-45
SLIDE 45

cnotes.txt Tue Mar 28 15:19:23 2017 89

Portable and Non-Portable Intrinsics

  • You can’t use an Intel x86 intrinsic when compiling

for ARM, and vice versa, unless both platforms have the same capability. But some builtins are portable. Here’s one that might be pretty portable: int __builtin_parity (unsigned int x); Here’s one that generates a particular fancy AVX2 instruction for AVX2. So only recent AMD/Intel platforms: v32qi __builtin_ia32_pmaddubsw256 (v32qi,v32qi)

cnotes.txt Tue Mar 28 15:19:23 2017 90

Embedded/inline assembly

  • For details:

http://www.ethernut.de/en/documents/arm-inline-asm.html In case you feel the need to break into assembly language in the midst of some C, you can use "inline assembly". That way, you can use some super-duper new machine instruction that does not yet have an intrinsic function. for (i = 0; i < 10; ++i) { asm( "mov r0, r0\n\t" "mov r0, r0\n\t" "mov r0, r0\n\t" "mov r0, r0" ); } [Note: a decent optimizing compiler will throw away all the code written above...]

slide-46
SLIDE 46

cnotes.txt Tue Mar 28 15:19:23 2017 91

Compilers and inline assembly

  • ----------------------------’

Early compilers supporting inline assembly would throw up their hands when encountering a glob of inline

  • assembly. They would assume it could do anything.

Any value in a register or memory location could possibly be trashed. So they did very conservative and inefficient things to compensate (eg, save all registers before, restore all after). Nowadays, you need to declare information about what are inputs to, output from the glob, and what gets clobbered by the glob. And then the compiler’s optimizer will feel free to rearrange/discard code in your glob, just like it feels free to rearrange code that its earlier phases generated. Details are too hairy for this course.

cnotes.txt Tue Mar 28 15:19:23 2017 92

Example (from earlier reference)

  • unsigned long ByteSwap(unsigned long val)

{ asm volatile ( "eor r3, %1, %1, ror #16\n\t" "bic r3, r3, #0x00FF0000\n\t" "mov %0, %1, ror #8\n\t" "eor %0, %0, r3, lsr #8" : "=r" (val) : "0"(val) : "r3" ); return val; } declared to clobber r3. Compiler is free to choose which register will be %1, which will be initialized to val. %0 is declared to be compiler-chosen register that will be the output (which is to be put into val)

slide-47
SLIDE 47

cnotes.txt Tue Mar 28 15:19:23 2017 93

Inline and Embedded Assembly in Keil

  • Your textbook’s Chapter 18 is about mixing assembler

and C with the Keil tools. In inline assembly, you cannot refer to any specific data register - compiler chooses for you. In embedded assembly you write a C header for a function and then write its body in assembly. Crossware would have its own way of doing things.

cnotes.txt Tue Mar 28 15:19:23 2017 94

C Compiler’s Symbol Table

  • Just like an assembler maintains a symbol table, so

does a C compiler. For an identifier, it will track such things as * name * type (int? (int *)?, function?) * scope (local? global-uninitialied? global-init?) * qualifiers (const?, volatile?) * location relative to + base of its global area + stack pointer or frame pointer [example]

slide-48
SLIDE 48

cnotes.txt Tue Mar 28 15:19:23 2017 95

Other C99 Features

  • * restrict qualifier: "while this pointer exists,

it is the _only_ way to reach the things that it points at". Helps compiler. * inline keyword. Functions declared inline as a hint to the compiler that it can insert their bodies in place of their calls. (Compilers can inline other functions anyway and can ignore inlining requests...) * long long int (at least 64 bits long) %lli * complex numbers (in various precisions) * variable sized arrays

cnotes.txt Tue Mar 28 15:19:23 2017 96

Other C11 Features

  • * alignment control (aligned_alloc() etc)

* support for multithreaded programming * options for bounds checking on arrays