Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
C Programming for microcontrollers (Joe Pardue, 2005).pdf
Скачиваний:
272
Добавлен:
12.08.2013
Размер:
4.55 Mб
Скачать

Chapter 6: C Functions and Program Structures

Chapter 6: C Functions and Program

Structures

Function Basics

About now you are probably wondering why you bought the Butterfly and all that cool hardware. Where are the projects? Let’s blow something up! Patience grasshopper, we’ll have a project at the end of this chapter and many more later. It will be worth it, I promise.

We’ve been using functions enough that by now you probably have a good intuitive feel for them, but Let’s be formal and define some things. First a ‘reuse’ of what was said earlier:

Encapsulation is a key idea in C programming and provides the possibility of making chunks of code convenient to use. And just as important, it provides a way to make tested code reusable while not allowing the programmer to mess with it and chance breaking something. These ideas are so important in software engineering that the C++ language was developed primarily to formalize these concepts and force their use.

One of the main functions of functions (har!) is to break computations up into logical chunks and separate them to help clarify the code. If you find yourself writing a function that seems to be doing two separable things, try separating it into two functions.

A function must be declared before it is defined somewhere, usually in a header file or before the main() function. For example:

void sendChar(char ) ;

Which tells the compiler that the sendChar() function takes a char as an argument and doesn’t return anything when finished. The compiler can use this information to make sure you are using it correctly when you make calls to the function.

A function definition is the function text as:

void sendChar(char myData)

87

Chapter 6: C Functions and Program Structures

{

// Do stuff with the variable ‘data’

}

Note that the argument now not only has the type ‘char’ but a specific variable ‘myData’. It doesn’t matter what you name the argument in the calling function, as long as the type matches, so:

sendChar(myByte);

This is just fine, since the sendchar function will use the data in ‘myByte’ as the data in ‘myData’ in the function definition. An important consideration is that the data in ‘myByte’ is copied to sendchar(myByte), but the variable ‘myByte’ is not sent. Think about this. In the calling function, ‘myByte’ is an alias for the address of some data, in this case a char. The called function takes that char and puts in memory at another address aliased, in this case, with the name ‘myData’. ‘myByte’ and ‘myData’ have the same value but are not stored in the same place. The function only sees a copy of ‘myByte’ not the actual ‘myByte’ itself. If the function chages the ‘myData’ variable, that change is not reflected in the calling functions ‘myByte’ variable. This is a source of a surprising number of bugs among novice C programmers. To clarify let’s make a function adder that adds two numbers.

void adder(unsigned char a1, unsigned char a2, unsigned char r)

{

r = a1 + a2;

if(r == 2) getrewarded(); else getboinked();

}

Let’s call it in main()

int main()

{

unsigned char add1 = 1; unsigned char add2 = 1; unsigned char results = 0;

adder(add1,add2,results);

88

Chapter 6: C Functions and Program Structures

if(results == 2) getrewardd(); else getboinked();

}

If you think 1 + 1 = 2 prepare to get boinked. You’ll getrewarded() in adder() and getboinked() in main(). In the adder function, r = 2, but this doesn’t change the ‘results’ in the parameter list in the function call to adder in the main() function.

Returns

Ouch! Boinking hurts, so Let’s make adder work right, we change the return type from void to char and declare r as an unsigned char:

char adder(unsigned char ad1, unsigned char a1)

{

unsigned char r;

r = a1 + a2;

if(r == 2) getrewarded(); else getboinked();

return r;

}

And in main we set ‘results’ equal to adder so it gets set to the data returned by adder:

int main()

{

unsigned char add1 = 1; unsigned char add2 = 1; unsigned char results = 0;

results = adder(add1,add2);

if(results == 2) getrewarded(); else getboinked();

}

Now we get two rewards. If we want to skip the reward we could write adder:

89

Chapter 6: C Functions and Program Structures

char adder(unsigned char ad1, unsigned char a1)

{

return a1 + a2;

}

And we have a concise and totally useless function. If we want to add 1 and 1, we just add them.

Variables External, Static, and Register

Another way to do the adder() thing would be to use and external variable (global). These are variables defined outside any function, usually in a header or before main() and are available for any function to use. We could have written:

void adder(unsigned char, unsigned char); unsigned char results = 0;

int main()

{

unsigned char add1 = 1; unsigned char add2 = 1;

adder(add1,add2);

if(results == 2) getrewarded(); else getboinked();

}

void adder(unsigned char ad1, unsigned char a1)

{

results = a1 + a2;

}

Which would work fine. Unless of course an interrupt triggered right after we set results in adder() and changed it to 3. Then when the interrupt finishes and we look at results in main() we get boinked again. This is a good reason to avoid external variables. You never know where they’ve been or what kind of nasty stuff they might track in. Also they permanently occupy memory, while defining ‘results’ in adder would only use memory when adder is called, and release the memory when finished.

90