Pages: [1] 2 3 ... 11   Go Down
Author Topic: Call for comments: Programming traps and tips  (Read 7909 times)
0 Members and 1 Guest are viewing this topic.
Global Moderator
Offline Offline
Brattain Member
*****
Karma: 499
Posts: 19065
Lua rocks!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

@Experienced programmers / Arduino users:

I am drawing up a list of tips and hints for a "sticky" or fixed web page. This is the current draft, below. Please comment, as you see fit, on:

  • Errors I have made
  • Suggested improvements
  • Suggested re-ordering of tips/traps
  • Any other ideas

Please, please, no four pages of discussion about whether or not goto is harmful. smiley

Note: Although it is usually bad form to edit a post after people have commented on it, to keep things in one place I will incorporate suggestions directly below. However to keep the comments meaningful the original text will be kept with a strikeout through it, as far as possible.



Trap: Using 'string' instead of "string".

eg.

Wrong! ...

Code:
char foo = 'start';

Correct:

Code:
char foo [] = "start";

Note that unlike some languages (eg. Lua, PHP) strings cannot be placed in single quotes. A letter in a single quote is used as a way of specifying (usually) a single character, eg.

Code:
char forwardCommand = 'F';



Trap: Reading too much from serial / ethernet.

eg.

Wrong! ...

Code:
if (Serial.available ())
  {
  char a = Serial.read ();
  char b = Serial.read ();
  }

Correct: See http://www.gammon.com.au/serial



Trap: Not using arrays.


Tip: Use arrays to hold multiple similar things.

eg.

Code:
int ledPin1 = 3;
int ledPin2 = 4;
int ledPin3 = 5;
int ledPin4 = 6;

Instead of:

Code:
int ledPin [4] = { 3, 4, 5, 6 };

Or preferably:

Code:
const byte ledPin [4] = { 3, 4, 5, 6 };



Trap: Trying to check a pin number rather than a pin.

eg.

Wrong! ...

Code:
const byte switchPin = 4;

...

if (switchPin == HIGH)
  {
  // switch is pressed
  }

Correct:

Code:
const byte switchPin = 4;

...

if (digitalRead (switchPin) == HIGH)
  {
  // switch is pressed
  }



Trap: Using "=" (assign) when you mean "==" (compare).

eg.

Wrong! ...

Code:
if (temperature = 10)

Correct:

Code:
if (temperature == 10)



Trap: Doing a serial print, or delay, inside an interrupt service routine.

eg.

Wrong! ...

Code:
ISR (TIMER0_OVF_vect)
  {
  Serial.print ("Timer overflowed!");
  delay (100);
  }

Neither will work properly because interrupts are turned off inside interrupt routines.

http://www.gammon.com.au/interrupts



Trap: Using too much RAM.

eg.

Code:
int myReadings [2000];

The above line will use 4 kB of RAM. The Uno and similar boards only have 2 kB of RAM.



Tip: Place string literals for printing inside the F() macro.

eg.

Instead of:

Code:
 Serial.print ("Program starting.");

Use:

Code:
 Serial.print (F("Program starting."));

This saves the string being copied from PROGMEM (program memory) into RAM (random access memory). You usually have a lot more program memory than RAM.



Trap: Trying to sprintf a float.

eg.

Code:
float foo = 42.56;
char buf [20];
sprintf (buf, "%f", foo);

On the Arduino, sprintf does not support floats.



Trap: Trying to sscanf a float.

eg.

Code:
float foo;
char buf [] = "123.45";
sscanf (buf, "%f", &foo);

On the Arduino, sscanf does not support floats.



Trap: Trying to add one to a variable in a way that is not defined.

eg.

Wrong! ...

Code:
i = i++;

The result of the above statement is not defined. That is, it is not necessarily "i + 1".

http://en.wikipedia.org/wiki/Sequence_point
http://c-faq.com/expr/seqpoints.html

Instead use:

Code:
i++;

Or:

Code:
i = i + 1;

A note about "undefined behavior":

http://en.wikipedia.org/wiki/Undefined_behavior

Quote
When an instance of undefined behavior occurs, so far as the language specification is concerned anything could happen, maybe nothing at all.



Trap: Calling a function without using parentheses.

eg.

Wrong! ...

Code:
void takeReading ()
  {
  // do something
  }
  
void loop ()
  {
  takeReading;   // <-- no parentheses
  }

The above code compiles but will not do anything useful.

Correct:

Code:
void takeReading ()
  {
  // do something
  }
  
void loop ()
  {
  takeReading ();
  }

The parentheses are required even if the function takes no arguments.



Trap: Doing multiple things after an "if" without using braces:

eg.

Wrong! ...

Code:
 if (temperature > 40)
    digitalWrite (furnaceControl, LOW);
    digitalWrite (warningLight, HIGH);

The indentation suggests that you want to do both things.

Correct:

Code:
 if (temperature > 40)
    {
    digitalWrite (furnaceControl, LOW);
    digitalWrite (warningLight, HIGH);
    }  // end if temperature > 40

Note the comments to make it clear what the closing brace refers to.



Trap: Overwrite the end of an array.

eg.

Wrong! ...

Code:
int foo [5];
foo [5] = 42;

The above code will corrupt memory. If you have 5 elements in an array, they are numbered: 0, 1, 2, 3, 4.



Trap: Overflowing an integer.

eg.

Wrong! ...

Code:
unsigned long secondsInDay = 60 * 60 * 24;

Small literal constants (like 60) are treated by the compiler as an int type, and have a maximum value of 32767. Multiplying such numbers together has a maximum value of 32767 still.

Correct:

Code:
unsigned long secondsInDay = 60UL * 60 * 24;

The "UL" suffix promotes the number to an unsigned long.

http://www.gammon.com.au/forum/?id=12146



Tip: Put things might vary, and other configuration numbers, at the start of a sketch as constants.


Tip: Put things that you might want to change (such as pin numbers, baud rates, etc.) at the start of a sketch as constants.

Instead of:

Code:
void setup ()
  {
  Serial.begin (115200);
  pinMode (5, OUTPUT);
  digitalWrite (5, LOW);
  pinMode (6, OUTPUT);
  digitalWrite (6, HIGH);

Use (for ease of changing later):

Code:
const unsigned long BAUD_RATE = 115200;
const byte LED_PIN = 5;
const byte MOTOR_PIN = 6;

void setup ()
  {
  Serial.begin (BAUD_RATE);
  pinMode (LED_PIN, OUTPUT);
  digitalWrite (LED_PIN, LOW);
  pinMode (MOTOR_PIN, OUTPUT);
  digitalWrite (MOTOR_PIN, HIGH);



Tip: Use a consistent and widely-accepted naming style for variables and constants.

In C it is traditional to put constants in all UPPER-CASE and variables in mixed upper/lower case.

The Arduino libraries tend to use camelCase (like "pinMode" and "digitalWrite") where you run words together (without underscores) starting with lower case, and using an upper case letter for each subsequent word.

However constants usually use all upper-case and thus have an underscore to separate individual words (like "NUM_DIGITAL_PINS").



Tip: Go easy with leading underscores in variable names.

In C++ these variable names are reserved:

Reserved in any scope, including for use as implementation macros:

  • identifiers beginning with an underscore and an uppercase letter
  • identifiers containing adjacent underscores (or "double underscore")

Reserved in the global namespaces:

  • identifiers beginning with an underscore

Therefore a global variable like this should not be used:

Code:
int _foo;

Also in any context a variable like this should not be used:

Code:
int _MotorPin;     // <--- underscore followed by upper-case letter
int My__Variable;  // <--- double underscores

I suggest not using leading underscores. If you want to differentiate class variables from non-class variables, use a trailing underscore.



Tip: Do not use goto

It is widely-accepted that the use of the goto statement in C/C++ is not only unnecessary, but harmful. There are occasional exceptions, but if you are reading a beginner's tutorial (like this) you definitely won't fall into the category of needing to use goto.

In almost every case where goto seems useful, it can be avoided by restructuring your code. For loops use "for", "while" or "do". To break out of a loop use "break". To leave a function use "return".

http://en.wikipedia.org/wiki/Goto#Criticism_and_decline
« Last Edit: September 27, 2013, 05:29:05 pm by Nick Gammon » Logged


Johannesburg. UTC+2
Offline Offline
Faraday Member
**
Karma: 105
Posts: 4687
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Nice!

Only comment: isn't the Not using arrays one more a Tip than a Trap?- (it's not actually wrong, just verbose)
Logged

The Elders of the Internet know who I am
I'm on LinkedIn: http://www.linkedin.com/in/jimbrownza

Global Moderator
Offline Offline
Brattain Member
*****
Karma: 499
Posts: 19065
Lua rocks!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Agreed. I was also thinking about style guidelines (eg. indentation, braces) but maybe that will ignite a "style war". smiley-razz
Logged


Global Moderator
UK
Offline Offline
Brattain Member
*****
Karma: 309
Posts: 26495
I don't think you connected the grounds, Dave.
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Trap:
Putting a semicolon after everything:
Code:
#define MY_CONSTANT 42;
Wrong  
Code:
#define MY_CONSTANT 42
Right

Code:
for (int i = 0; i < MY_CONSTANT; i++);
(almost certainly) wrong
Logged

"Pete, it's a fool looks for logic in the chambers of the human heart." Ulysses Everett McGill.
Do not send technical questions via personal messaging - they will be ignored.

Global Moderator
Offline Offline
Brattain Member
*****
Karma: 499
Posts: 19065
Lua rocks!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Good point, I knew I would forget a few things like that.

Probably a comparison between #define and "const int" would be in order.
Logged


Global Moderator
UK
Offline Offline
Brattain Member
*****
Karma: 309
Posts: 26495
I don't think you connected the grounds, Dave.
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Trap:
Over prettifying comments
Code:
// I want my comment to look symmetrical \\
int butTheCompilerNeverSeesThisDeclaration;
Logged

"Pete, it's a fool looks for logic in the chambers of the human heart." Ulysses Everett McGill.
Do not send technical questions via personal messaging - they will be ignored.

Offline Offline
Newbie
*
Karma: 0
Posts: 37
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Agreed. I was also thinking about style guidelines (eg. indentation, braces) but maybe that will ignite a "style war". smiley-razz

Maybe mentioning the importance of a consistent style and refering to some style guides as examples ?


Quote
Tip: Do not use goto

It is widely-accepted that the use of the goto statement in C/C++ is not only unnecessary, but harmful.

Add a reference to Edsger Dijkstra's 1968 paper?


Quote
Tip: Put things might vary, and other configuration numbers, at the start of a sketch as constants.

Better (?): Tip: Put things that might vary, and other configuration numbers, at the start of a sketch as constants.



Quote
Tip: Put things might vary, and other configuration numbers, at the start of a sketch as constants.

...

In C it is traditional to put constants in all UPPER-CASE and variables in mixed upper/lower case.

The Arduino libraries tend to use camelCase (like "pinMode" and "digitalWrite") where you run words together (without underscores) starting with lower case, and using an upper case letter for each subsequent word.

However constants (as suggested above) use all upper-case and thus an underscore to separate individual words (like "NUM_DIGITAL_PINS").

I think the explanation is a separate tip.


Logged

Offline Offline
God Member
*****
Karma: 32
Posts: 830
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

All many/most of your "tips and traps" so far are for generic C and C++, and there are many fine introductions covering all this (and much more) already available on the Internet.  However, there probably is a need to cover "tips and traps" for Arduino-specific peculiarities, i.e., where it departs from C/C++ standards (the C preprocessor especially).

e.g.: http://forum.arduino.cc/index.php?topic=190210.0

Edit: "Tip: Put things might vary, and other configuration numbers, at the start of a sketch as constants."

I think I know what you mean, but in general, things that might vary need to be variables, and things that don't should be declared constants.

What you are getting at, of course, is that constant values that are used in several places in the program should be declared at the start of the sketch as constants with meaningful names, aiding both readability and maintainability of the program. Might be clearer with a reword, especialliy for newbies.

« Last Edit: September 27, 2013, 04:27:25 am by pico » Logged

WiFi shields/Yun too expensive? Embeddedcoolness.com is now selling the RFXduino nRF24L01+ <-> TCP/IP Linux gateway: Simpler, more affordable, and even more powerful wireless Internet connectivity for *all* your Arduino projects! (nRF24L01+ shield and dev board kits available too.)

Global Moderator
Offline Offline
Brattain Member
*****
Karma: 499
Posts: 19065
Lua rocks!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
many/most of your "tips and traps" so far are for generic C and C++, and there are many fine introductions covering all this (and much more) already available on the Internet.

That's true, and/but I was trying to unify the ones we commonly see into one page.

Quote
However, there probably is a need to cover "tips and traps" for Arduino-specific peculiarities ...

Yes, a good point, and maybe a tip or two about the way include files are handled, and how to build multi-file projects in the IDE would be in order.

There's a fine line between stating the obvious, covering too much (and having the page be unwieldy) or covering too little.
Logged


Johannesburg. UTC+2
Offline Offline
Faraday Member
**
Karma: 105
Posts: 4687
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Maybe have two pages....

  • Tips and Traps: Beginners
  • Tips and Traps: Experienced C / C++ users
Logged

The Elders of the Internet know who I am
I'm on LinkedIn: http://www.linkedin.com/in/jimbrownza

Offline Offline
God Member
*****
Karma: 32
Posts: 830
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Maybe have two pages....

  • Tips and Traps: Beginners
  • Tips and Traps: Experienced C / C++ users

Maybe better to have two documents, or two sections within the one document:

a) General tips and traps (C and C++ programming)
b) Arduino-specific tips and traps (Ardunio differences wrt C/C++ standards)

I don't really see it as an experienced programmer/beginner dichotomy, because even beginners will get confused if also learning from another text that assumes standard C/C++.
« Last Edit: September 27, 2013, 04:35:13 am by pico » Logged

WiFi shields/Yun too expensive? Embeddedcoolness.com is now selling the RFXduino nRF24L01+ <-> TCP/IP Linux gateway: Simpler, more affordable, and even more powerful wireless Internet connectivity for *all* your Arduino projects! (nRF24L01+ shield and dev board kits available too.)

UK
Offline Offline
Shannon Member
****
Karma: 223
Posts: 12630
-
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I would suggest always using braces around conditional code. It makes the intended scope of the condition explicit (so the reader doesn't have to guess what was intended) and avoids the risk of dangling else statements.

Code:
if(a == true)
    if(b == true)
        c = 1;
  else
      c = 2; // when does this execute?

It also avoids problems where the condition only controls a single statement, which can be subtly dangerous if a second statement is added subsequently, especially if that second statement is the result of macro expansion.
Code:
if(a == true)
    Serial.print("Value is"); Serial.print(b);
As a general guide:
Don't use macros to define constant values - use const variables.
Don't use macros to generate executable statements - use inline functions.

Specifically for Arduino:
When defining a function that receives or returns a user-defined type, define the type in a header file and #include that in the .ino file. (This prevents the IDE from breaking your code by inserting a function prototype in the wrong place.)
Logged

I only provide help via the forum - please do not contact me for private consultancy.

Global Moderator
Offline Offline
Brattain Member
*****
Karma: 499
Posts: 19065
Lua rocks!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
Tip: Put things might vary, and other configuration numbers, at the start of a sketch as constants.

Better (?): Tip: Put things that might vary, and other configuration numbers, at the start of a sketch as constants.

I think I know what you mean, but in general, things that might vary need to be variables, and things that don't should be declared constants.

Reworded to address both those points.

I think the explanation is a separate tip.

Done.

Quote
Add a reference to Edsger Dijkstra's 1968 paper?

I can't see a ready URL that links directly to it. I'll add a link to the Wikipedia article.
Logged


Global Moderator
Offline Offline
Brattain Member
*****
Karma: 499
Posts: 19065
Lua rocks!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

I would suggest always using braces around conditional code. It makes the intended scope of the condition explicit (so the reader doesn't have to guess what was intended) and avoids the risk of dangling else statements.

I know where you are coming from, but I always find this sort of thing unnecessarily complex:

Code:
  if (index >= MAX_INDEX)
    {
    index = 0;
    }

Compared to:

Code:
  if (index >= MAX_INDEX)
    index = 0;

That's doubled the lines of code for no real gain.

Certainly for nested "if"s, I would be very inclined to use the braces or things just get crazy.

Quote
As a general guide:
Don't use macros to define constant values - use const variables.
Don't use macros to generate executable statements - use inline functions.

Yes, I think a short mention of constants would be in order.

Quote
Specifically for Arduino:
When defining a function that receives or returns a user-defined type, define the type in a header file and #include that in the .ino file. (This prevents the IDE from breaking your code by inserting a function prototype in the wrong place.)

Yes, although this tends not to hit beginners so much. Plus you can do your own function prototypes these days to work around that.
Logged


Global Moderator
Offline Offline
Brattain Member
*****
Karma: 499
Posts: 19065
Lua rocks!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Whoops! Hit the 9500 byte posting limit. More tips follow:



Tip: Don't try to out-think the compiler

The compiler aggressively optimizes your code. In general you don't need to try to improve on its performance by attempting your own optimizations, especially if that makes the code obscure and hard to maintain. In particular you almost never need to use assembler code to get speed improvements, because the compiler generates good assembler code from your C source.

However you can help the compiler by choosing good data types. For example, for small numbers use char or byte, for medium size numbers int or unsigned int, and for larger numbers long or unsigned long. The limits for such types on the Arduino (8-bit) platform are:

Code:
char:                 -128  to         +127
byte:                    0  to         +255
int:                -32768  to       +32767
unsigned int:            0  to       +65535
long:          -2147483648  to  +2147483647
unsigned long:           0  to  +4294967295

Note that for storing times (eg. from millis() or micros() function calls) you should use unsigned long.

Also the String class tends to be slow, and also a bit of a memory hog. Try to avoid using it.



Trap: Don't put a semicolon at the end of every line

Semicolons end statements. However "if", "for" and "while" are compound statements, so they should not have a semicolon after them like this:

Wrong! ...

Code:
 if (temperature > 40);    // <----- this semicolon is not required!
    {
    digitalWrite (furnaceControl, LOW);
    digitalWrite (warningLight, HIGH);
    }

  for (int i = 0; i < 10; i++);   // <----- this semicolon is not required!
    digitalWrite (i, HIGH);

The semicolons above (as indicated) terminate the "if" and "for" so they don't do anything useful. The lines following them are just unconditional blocks of code which are always executed, once.

Correct:

Code:
 if (temperature > 40)
    {
    digitalWrite (furnaceControl, LOW);
    digitalWrite (warningLight, HIGH);
    }

  for (int i = 0; i < 10; i++)
    digitalWrite (i, HIGH);

Similarly this is wrong:

Code:
#define LED_PIN 10;    // <--- no semicolon!
#define LED_PIN = 10;  // <--- no semicolon, no "=" symbol

Correct:

Code:
#define LED_PIN 10

Or, better still:

Code:
const byte LED_PIN = 10;

Using a const rather than a #define has various advantages, including the one of consistency. Now the semicolon and "=" symbol are required. This is consistent with the way you write variables. However there is no performance or space penalty for using constants like this (compared to using #define).



Trap: Don't over-prettify your comments

Wrong! ...

Code:
// I want my comment to look symmetrical \\
int butTheCompilerNeverSeesThisDeclaration;

The comment looks cute, but the trailing backslash makes the following line part of the comment (because of line folding).

Correct:

Code:
// Here is my comment with no trailing backslash
int someVariable;



Trap: Trying to initialize multiple variables

For example:

Code:
int x, y, z = 12;

Only z is initialized there.

Good:

Code:
int x = 1, y = 2, z = 12;

Better:

Code:
int x = 1;
int y = 2;
int z = 12;



Trap: Not initializing local function variables

Wrong! ...

Code:
void calculateStuff ()
  {
  int a;

  a = a + 1;

Since "a" was not initialized, adding one to it is undefined.

http://en.wikipedia.org/wiki/Undefined_behavior



Trap: Trying to work on a "set"

Wrong! ...

Code:
digitalWrite ((8, 9, 10), HIGH);

Whilst the above will compile, it only sets a single pin high (pin 10).

http://en.wikipedia.org/wiki/Comma_operator

Correct:

Code:
digitalWrite (8, HIGH);
digitalWrite (9, HIGH);
digitalWrite (10, HIGH);

Or:

Code:
for (byte i = 8; i <= 10; i++)
  digitalWrite (i, HIGH);



Trap: Returning a pointer to a local variable

Wrong! ...

Code:
char * getString ()
{
  char s [] = "abc";
  return s;
}

The string "s" is allocated on the stack and goes out of scope when the function returns, and is no longer valid. There are various work-arounds, one would be:

Better:

Code:
char * getString ()
{
  static char s [] = "abc";
  return s;
}

That isn't perfect (you might call getString twice and try to use both returned values) however at least it won't actually crash.

Other work-arounds are:

  • Make the variable you are planning to change global.
  • Pass the variable by reference and change that.



Trap: Leaving a semicolon off after a "return"

Wrong!

Code:
 if (a < 10)
    return     // <----- no semicolon!
  a = a + 1;

The code above compiles as if it were written:

Code:
 if (a < 10)
    return a = a + 1;



Tip: Let the compiler do the work for you

A. Instead of working out how many seconds there are in a day on a calculator and then typing it in, for example:

Code:
const unsigned long secondsInDay = 86400;  // 60 * 60 * 24

Let the compiler do it:

Code:
const unsigned long secondsInDay = 60UL * 60 * 24;

B. Let the compiler work out how big things are:

Instead of:

Code:
char buffer [20];

// later ...

if (i < 20)
  {
  buffer [i] = c;
  }

Use this:

Code:
char buffer [20];

// later ...

if (i < sizeof (buffer))
  {
  buffer [i] = c;
  }

Now, if you ever change 20 to 30, the code still works properly, without having to remember to change it in multiple places.

For arrays of things larger than one byte you can use this macro to find how large the array is:

Code:
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))

For example:

Code:
int myArray [20];

int numberOfItems = ARRAY_SIZE (myArray);   // <--- will be 20 in this case

C. Let the compiler work out how many things you put into an array of (say) pin numbers:

Instead of:

Code:
const byte pinNumbers [5] = { 5, 6, 7, 8, 9 };

Use:

Code:
const byte pinNumbers [] = { 5, 6, 7, 8, 9 };

Later you can use ARRAY_SIZE to find how many elements there actually are in the array.



Trap: Doing too much in a constructor

There is a subtle problem with initializing things in a class constructor, particularly if the constructor might be called at the global level (that is, not inside a function).

Example:

Code:
myClass::myClass ()  // constructor
  {
  Wire.begin (32);  // initialize I2C library
  whenStarted = millis ();
  Serial.begin (115200);
  Serial.println ("Ready to go.");
  }

The problem is that libraries like Wire, Serial, and the timers may not have been initialized at this time. In other words, your constructor may have been called before their constructor.

You are best off doing minimal things in the class constructor, and making a "begin" function (like Serial.begin, Wire.begin, etc.) and calling that in "setup". Acceptable things to do in a constructor are to store simple types (eg. integers like pin numbers).

http://www.parashift.com/c++-faq/static-init-order.html



Tip: Use "else" rather than testing for the same thing twice

Bad:

Code:
if (a == 5)
  {
  // do something
  }
if (a != 5)
  {
  // do something else
  }

Good:

Code:
if (a == 5)
  {
  // do something
  }
else
  {
  // do something else
  }



Tip: Use "switch/case" rather than lengthy "if" tests

Bad:

Code:
if (command == 'A')
  {
  // do something
  }
else if (command == 'B')
  {
  // do something
  }
else if (command == 'C')
  {
  // do something
  }
else
  {
  // unexpected command
  }

Good:

Code:
switch (command)
  {
  case 'A':
        // do something
        break;

  case 'B':
        // do something
        break;

  case 'C':
        // do something
        break;

  default:
        // unexpected command
        break;
  }  // end of switch



Trap: Be careful with recursion

These micro-controllers don't have much memory. Be cautious when using recursive functions (functions that call themselves).

In particular this will fail spectacularly:

Code:
void loop ()
  {
  // do stuff
 
  loop ();    //  <--- recursion!
  }
« Last Edit: September 28, 2013, 06:43:32 am by Nick Gammon » Logged


Pages: [1] 2 3 ... 11   Go Up
Jump to: