C language

From ScienceZero
Revision as of 04:31, 24 January 2011 by Bjoern (Talk | contribs) (Control flow)

Jump to: navigation, search

Things to remember about the C language if you want to keep sane

There are countless ways of tripping yourself up using the C language. The compiler will happily accept what you write, no matter how stupid the mistake is. This document points out some of the most common things that you need to know.

The stack

The stack has a limited space allocated to it, all your variables and temporary storage used by function calls are stored on the stack. When the limited space runs out you will not get a warning, your program will simply fail. You need to know how to adjust the size of the stack so it fits the requirements of your program.

Symptoms:

  • The program counter seems to jump around at random
  • Corrupted variables and data
  • Interrupt functions fail

The heap

The heap is a data structure that is used to keep track of free and allocated memory. If the heap is not initialized any attempts at reserving memory with malloc will fail.

Symptoms:

  • Crashes when you try to access memory

Declarations

#define

volatile

The volatile keyword tells the compiler that the following object is subject to sudden change in a way that is not described in the source code. For example a RS-232 data register that receive data from the outside. Volatile forces the compiler to generate the code that access the memory location each time instead of cache it in a register. Can be applied to any declaration.

Symptoms of missing volatile statements:

  • Code fails when you enable compiler optimizations
  • Code fails when interrupts or DMA/Hardware peripherials are enabled
I2C1_CR1 (*((volatile unsigned long *) 0x40005400))

extern

The extern keyword indicates that the actual storage and initial value of a variable, or body of a function, is defined elsewhere, usually in a separate source code module.

extern int counter;

static

The static keyword tells the compiler to preserve the last value of the variable between successive calls to that function.

static int counter;

const

Read only. Can be applied to any declaration.

const volatile unsigned long int base_address = 0xFFFF;

register

Tells the compiler to force a variable to say in a register for improved performance. The compiler can ignore the keyword and use some other form of optimisation.

register unsigned int i;

Pointers

Pointer subtraction

The following statements apply to all pointers in C. They also apply to pointers, other than pointers to members, in C++:

  • When one pointer is subtracted from another, the difference is obtained as if by the expression: ((int)a - (int)b) / (int)sizeof(type pointed to)
  • If the pointers point to objects whose size is one, two, or four bytes, the natural alignment of the object ensures that the division is exact, provided the objects are not packed.
  • For packed or longer types, such as double and struct, both pointers must point to elements of the same array.

Control flow

for

  • for (initialise; test; modify) { statement } ;

do

do { statement } while (expression) ;

while

while (expression) { statement } ;

Switch

switch(exspression)
{
	case constant-expression :
	//code
	break;
	default: // This is taken if no case statements match.
}

break

Pass control to the statement after the loop

continue

Pass control to the start of the loop

If

  • if (expression) { statement }
  • if (expression) { statement } else { statement }
  • if (expression) { statement } else if (expression) else { statement }

? (ternary condition)

Is this wise? It seems like more pain and very little gain...

  • (expression1) ? (expression2) : (expression3)
z = (a > b) ? a : b;
   is the same as
if (a > b) z = a; else z = b;

goto

  • goto label

Artithmetic and logical operations

Bitwise logical operations

  • & AND
  • | OR
  • ^ EOR
  • ~ NOT

Shifts (ARM compilers)

  • Right shifts (>>) on signed quantities are arithmetic (implementation defined).
  • Any quantity that specifies the amount of a shift is treated as an unsigned 8-bit value.
  • Any value to be shifted is treated as a 32-bit value.
  • Left shifts (<<) of more than 31 give a result of zero.
  • Right shifts of more than 31 give a result of zero from a shift of an unsigned value or positive signed value. They yield –1 from a shift of a negative signed value.


  • >> - Right shift
  • << - Left shift
  • Rotate
    • Rotate right (ROR) for unsigned int can be implemented as r0 = ((r0 >> n) | (r0 << ((sizeof(unsigned int) * 8) - n)));
    • Rotate left (ROL) for unsigned int can be implemented as r0 = ((r0 << n) | (r0 >> ((sizeof(unsigned int) * 8) - n)));

&& || ==

!= > < >= <=

+= -=

  • =

/= >>= <<=

Type specifiers

Data types (ARM C and C++)

  • char 8 bits (signed or unsigned is implementation defines so always specify)
  • short 16 bits
  • int 32 bits
  • long 32 bits
  • long long 64 bits (The low word of a long long is at the low address in little-endian mode, and at the high address in big-endian mode.)
  • float 32 bits
  • double 64 bits
  • long double 64 bits
  • All pointers 32 bits
  • bool (C++ only) 32 bits

Memory alignement in bits is word length or 32 whichever is smallest

Other

  • void
  • signed
  • unsigned

type casting subroutines void return global vs local

& (unsigned int *)

arrays multiple dimensions array pointers, 1d, 2d string, terminating character /n /r /t escape characters vs ""

character and on what type of lines is belongs on


include files "file" <file> .c .h included libraries