48
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

Beginning C for Java Programmers ...owen/courses/2253-2017/slides/cnotes-2up.pdfcnotes.txt Tue Mar 28 15:19:23 2017 11 Simple C program ----- #include #define N 5 int

  • Upload
    leliem

  • View
    218

  • Download
    1

Embed Size (px)

Citation preview

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

Beginning C for Java Programmers ---------------------------------

C started in the early 1970s as a systems-programminglanguage.

Higher level than assembly language.

Lower level than most other languages.

K & R : Kernighan and RitchieInfluential 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 declaredbefore any statements in any {.....} block.

Array syntax is not as "logical" as Java’s

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 constantsand 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 textuallyreplaced by 12*3*z

#undef BAR will "undefine" BAR. After this, BAR(3*z) remains as is.

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 programmerlooking 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 quotemarks 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

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 beevaluated 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 **

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

Conditional Compilation part II--------------------------------

Conditional compilation is often used to tailorthe code for a particular models of computer.

And to ensure that a given "include file" isn’tseen 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)

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

Simple C program-----------------

#include <stdio.h>#define N 5int 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)

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)

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

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

Library header files--------------------

One of the main things contained in libraryheader files (eg, <stdio.h>) are thefunction prototypes for the routines thatthe 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() {....}

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

Order of Parameter Evaluation----------------------------- For functions with multiple parameters, it isundefined in which order the parameters areevaluated.

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

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

Stack Frames------------Compilers generate stack frames according to theapproved calling conventions for that system.

Look at the Resources section: ARM StackFrame Layout (Windows CE 5.0).

More later about "alloca()".

Appears consistent with AAPCS.

Note the "Frame Pointer". Some calling conventionsuse frame pointers (aka BP); others don’t. This onerequires 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 thatcan 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 thanyou do in C.

int i = 3.14; //narrowing, Java needs typecastfloat f = 3; // widening, Java is also ok with this

my_arg_should_be_float(3.14); // narrowing, Java cast

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 putcharscanf 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.

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

Getchar and the EOF bug-----------------------

Function getchar() returns a character from thestandard input stream (normally, the keyboard).

If there are no more characters (standard inputhas 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 happensuntil a newline is hit. (Until then you can edityour keyboard input).

And many systems buffer output: nothing actuallygets sent to the screen (or to a file) until anewline is sent, or more than some number of kbof data is ready to send.

Buffered I/O is good for system efficiency but hardon programer heads.

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

Data Types----------

Basic types are sorta similar to Java: int, double, float, long, short, charinteger 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 dependentlanguage.

So an int means different things on differentplatforms. (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.

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 thesetypes.

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.

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 thecompiler may force you to do a lot of typecastingwhen you insert one or two uses.

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 assumethat 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

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 compileralso knows the type of the thing that is in memoryat that address. More importantly, the compilerknows how many memory addresses are taken up byeach 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 muchlike a pointer, except you are very limited inwhat you can do with it.

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 thatis 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 *operator.

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

Declaring a Pointer Variable-----------------------------

int *foo; <-- declares a pointer to an intfloat *bar; <-- bar points to a floatint **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 other 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

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 thisor int bar (int *q) if foo cannot.

or 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 itusing unary & operator, which we sometimes callthe "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.)

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

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 thetype of the pointed-to information is unknownor temporarily irrelevant.

C provides the "void pointer" for this. Youcannot do much with a void pointer - eg, youcannot dereference it.

You can typecast a void pointer to any otherpointer type, though.

void *foobar;

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 memoryJava uses when you use the "new" operator.

In C, you can ask for a block of heap memory usingthe malloc() library function. Argument is thenumber of bytes you want. Result returned as a(void *) that you can typecast to the desired ptrtype.

Any memory taken with malloc() should eventuallybe 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 Cpointers. (Good for your inner 11-year-old.)

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

More on the Heap----------------The heap is a region of memory, where chunks of thismemory 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 eventuallya malloc() may find there is no free block thatis big enough.

Maybe all memory is in use. Maybe not, but onlysmall blocks are available.

When this happens, the heap needs to grow. Itexpands 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 of 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 memoryaddresses. We’d like to be able to support almostall addresses for the stack (highly recursive pgm) oralmost all addresses for the heap (malloc-intensive).

Classic approach: Stack starts at a very high addressand grows down; heap starts at a small address andgrows up. As long as the top of the stack doesn’tmove into the heap area, we are okay.

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-onlyor flash memory, whereas global variables,stack and heap need to be in RAM. Constants canbe a part of the global initialized region, or(as with our ARM examples) in with the machine code.

Many calling conventions (dunno about AAPCS) dedicateregisters to point at the bases of theglobal variable or constants regions. Facilitateuse 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 itsprogram in ROM or flash memory, if you want to havean OS load various apps or programs on demand, youwill need for all memory areas to be in RAM.

Putting code into RAM enables a historical horror called self-modifying code. The program canoverwrite some of its own machine code while it isrunning. Commonly write NOP (no-op) instructionson top of things you want to disable. Or, writeBL instructions into strategically placed NOPs inthe code.

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 youdeclare 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 *)

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 seewhether there is a bounds error.

Not the case in C, where you will read junk and write corruption...

C11 may help with this.

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 withother initialized globals (different region than theuninitialized 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; <-- allowedA = pa; <-- not allowed, array name is constant

*pa = 5; <-- same as A[0] = 5

*(pa+i) is same as A[i] or pa[i]

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 theith element of the array. If each array elementoccupies 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 ofthe same array, you are allowed to subtract them.Result is the number of array elements betweenthem.

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 allowedto compare them for ==, !=, >, >= etc.

The integer 0 is used as NULL in C.

In earlier versions C, pointers are integers weresomewhat interchangeable. Not any more. However,0 is special.

It is okay to do a pointer comparison between apointer within an array and a pointer that is ONEpast the end of an array.

0 (as a pointer or integer) is equivalent to falsein C.

Hence if ( p && *p == ’a’) ..... or if ( p != 0 && *p == ’a’)....

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.

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

Valgrind and GCC options------------------------

Manual memory management is the source of muchefficiency 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 compilersuite has added options that let you check forsimilar corruption and also use of uninitializedvalues.

-Wuninitialized -Wmaybe-uninitialized-fsanitize variations such as -fsanitize=address or -fsanitize=undefined

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

Alloca--------

The alloca(s) function is like malloc() exceptthat it generates space in the stack frame.

Can be more efficient, but its use is discouraged.

Space created with alloca is automatically recoveredwhen the function returns.

DO NOT CALL FREE on space gotten with alloca

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

Function Pointers-----------------

Some of the neat things that object-oriented folksare used to doing - you can accomplish them in Cusing "function pointers".

A function pointer is essentially the starting memory address of a piece of code. The compilerknows the type of the function (its return typeand 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 *));or 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);}

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

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

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

Structs and Typedef-------------------

Repeatedly having to type the keyword "struct" whendeclaring 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 anactual object, you need "new".

So assignment jRef1 = jRef2 means that there is 1 object, 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 structspoint1 = point2; <-- still 2 different structspoint1.xcoord - 4.2; <-- no change to point2.xcoord

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.

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 one of the members of the struct.

... (*pt).xcoord...

Parenthesis needed due to operator precedence.

As a shorthand, we have the arrow operator, pt->xcoordwhich 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; }

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 astruct BEFORE the compiler has seen the actualdefinition of the struct. Useful with parametersif 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;};

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

Unions-------In a struct, the members are laid out in memory, one after another (with possible padding).

A union is basically a struct where all the membersoverlap 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 iboth starting at the same address (not padding oneand not the other). This may not be technically safewith C89. But it is apparently safe in C99.(cf Wikipedia page on "type punning")

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 aplatform 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 6bits is system dependent, as are most aspects ofbit fields. Good for very low-level un-portable code.

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, witha 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.

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

Interpreting Errno------------------

A function perror looks at errno and prints an errormessage 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 whetherend-of-file has been reached.

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’dconsider them more "modern".

Intrinsics and inline assembly can be contrasted withjust writing some subroutines in assembly, and thenlinking the resulting object code with object coderesulting 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 libraryfunction. However, the compiler will have somebaked-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.

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 assemblylanguage in the midst of some C, you can use"inline assembly". That way, you can use somesuper-duper new machine instruction that does not yethave 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 awayall the code written above...]

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

Compilers and inline assembly-----------------------------’Early compilers supporting inline assembly would throwup their hands when encountering a glob of inlineassembly. They would assume it could do anything.Any value in a register or memory location couldpossibly be trashed.

So they did very conservative and inefficient thingsto compensate (eg, save all registers before, restoreall after).

Nowadays, you need to declare information aboutwhat are inputs to, output from the glob, and whatgets 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 choosewhich register will be %1, which will be initializedto val. %0 is declared to be compiler-chosen registerthat will be the output (which is to be put into val)

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

Inline and Embedded Assembly in Keil------------------------------------

Your textbook’s Chapter 18 is about mixing assemblerand 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 afunction 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]

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