Languages/C/tips

(Difference between revisions)
Jump to: navigation, search
m
Line 2: Line 2:
 
= C tips, tricks and... '''traps''' =
 
= C tips, tricks and... '''traps''' =
 
After ten years of C programming, let me gather some piece of code I saw...
 
After ten years of C programming, let me gather some piece of code I saw...
 +
 +
== Trap : delay loop optimized away ==
 +
Modern compiler will remove stupid code which seems to do nothing.
 +
<source lang='C'>
 +
 +
/**
 +
* This loop will probably take 0 nanosecond, it does really nothing
 +
* and the compiler can throw it away.
 +
*/
 +
void zero_delay(void)
 +
{
 +
    int i;
 +
 +
    for (i = 0 ; i < 10*1000 ; i++)
 +
    {
 +
    }
 +
}
 +
 +
/**
 +
* This loop will take some time, but using the cpu for wasting time is not a
 +
* so good idea.
 +
*/
 +
void dumb_delay(void)
 +
{
 +
    int i;
 +
 +
    for (i = 0 ; i < 10*1000 ; i++)
 +
    {
 +
        asm("nop"); /* replace with the nop instruction from your cpu*/
 +
    }
 +
}
 +
 +
/**
 +
* The good way(tm)
 +
*/
 +
void smart_delay(void)
 +
{
 +
  /* Initialize a timer for the delay you want */
 +
  /* put the cpu to sleep until the timer has fired */
 +
 +
  /* In any case if your OS already provide this kind of function, use it !*/
 +
  #include <unistd.h>
 +
  usleep(33);
 +
}
 +
</source>
 +
 +
== Trap : compilation and memory mapped registers ==
 +
Don't forget to use the <code>volatile</code> keyword when accessing a register
 +
 +
== Tip : Use static functions ==
 +
Trust the compiler, use <code>static</code> (<code>inline</code>) function instead of <code>#define</code>,
 +
The function is far more readable, and a decent compiler will generate exactly the same code.
 +
 +
<source lang='C'>
 +
<stdint.h>
 +
 +
/* This function */
 +
static uint8_t increment_func(uint8_t a)
 +
{
 +
    return ++a;
 +
}
 +
 +
/* Will work as fast as this define */
 +
#define increment(a) ((a)+1)
 +
 +
</source>
 +
 +
== Trick : Initializing a struct ==
 +
<source lang='C'>
 +
<stdint.h>
 +
<string.h>
 +
 +
struct toto_t
 +
{
 +
    uint8_t a;
 +
    uint8_t b;
 +
    uint8_t c;
 +
}
 +
 +
void init_this_struct(struct toto_t *toto)
 +
{
 +
    /* This is the dumb way */
 +
    toto->a = 0;
 +
    toto->b = 0;
 +
    toto->c = 0;
 +
 +
    /* This is the smart way */
 +
    memset(toto, 0x0, sizeof(*toto));
 +
}
 +
</source>
  
 
== Tip : Write readable code ==
 
== Tip : Write readable code ==

Revision as of 09:00, 13 July 2012

Contents

C tips, tricks and... traps

After ten years of C programming, let me gather some piece of code I saw...

Trap : delay loop optimized away

Modern compiler will remove stupid code which seems to do nothing.

/**
 * This loop will probably take 0 nanosecond, it does really nothing
 * and the compiler can throw it away.
 */
void zero_delay(void)
{
    int i;
 
    for (i = 0 ; i < 10*1000 ; i++)
    {
    }
}
 
/**
 * This loop will take some time, but using the cpu for wasting time is not a
 * so good idea.
 */
void dumb_delay(void)
{
    int i;
 
    for (i = 0 ; i < 10*1000 ; i++)
    {
        asm("nop"); /* replace with the nop instruction from your cpu*/
    }
}
 
/**
 * The good way(tm)
 */
void smart_delay(void)
{
   /* Initialize a timer for the delay you want */
   /* put the cpu to sleep until the timer has fired */
 
   /* In any case if your OS already provide this kind of function, use it !*/
   #include <unistd.h>
   usleep(33);
}

Trap : compilation and memory mapped registers

Don't forget to use the volatile keyword when accessing a register

Tip : Use static functions

Trust the compiler, use static (inline) function instead of #define, The function is far more readable, and a decent compiler will generate exactly the same code.

<stdint.h>
 
/* This function */
static uint8_t increment_func(uint8_t a)
{
    return ++a;
}
 
/* Will work as fast as this define */
#define increment(a) ((a)+1)

Trick : Initializing a struct

<stdint.h>
<string.h>
 
struct toto_t
{
    uint8_t a;
    uint8_t b;
    uint8_t c;
}
 
void init_this_struct(struct toto_t *toto)
{
    /* This is the dumb way */
    toto->a = 0;
    toto->b = 0;
    toto->c = 0;
 
    /* This is the smart way */
    memset(toto, 0x0, sizeof(*toto));
}

Tip : Write readable code

  • First, write and test code that works can be easily understood.
  • If it has no efficiency (CPU or memory) problems, let it.

Tip : dummy read of a register

Some register peripherals, especially on embedded systems must be read to be cleared. Here is a nice way of doing it.

/* Suppose this is the address of a memory mapped status register */
volatile uint32_t *some_status_register;
 
 
/**
 * Now suppose that we want to clear it, so here is a way
 */ 
void read_and_discard_status_reg(void)
{
    uint32_t dummy;
 
    dummy = *some_status_register;
}
 
/**
 * And here is another way, cleaner
 */ 
void read_and_discard_status_reg(void)
{
    /* the void cast will do the read, sure ;) */
    (void)*some_status_register;
}

Trap : if (a = b)

Remember, '=' is different from '=='. Any decent compiler used with decent options will warn you.

int a = 12;
int b = 13;
 
if (a = b)
{
   printf("12 = 13 ?!?");
}

Tip : if (result = function_call()) warning

Your compiler warn you if you test the return value in the if ? add one stage of braces around and it's gone

/* This should do a warning */
if (a = strlen("toto)")
{
 
}
 
/* This will not warn */
if ((a = strlen("toto"))
{
 
}

Trap : sizeof('a')

Here is a bad joke, what is sizeof('a') ?

#include <stdio.h>
 
int main(int argc, char *argv[])
{
        return printf("sizeof('a') = %ld\n", sizeof('a'));
}

And the result is... 4, or at least sizeof(int) which depends on your compiler!



Tip : signed or unsigned char ?!?

gcc char type is neither signed nor unsigned. In the following code, gcc will only compile the test_char function without warning. Solution : cast your unsigned char* to a char* ((char*)msg)

#include <stdint.h>
#include <string.h>
 
int test_unsigned_char(const unsigned char *msg)
{
        return strlen(msg);
}
 
int test_signed_char(const signed char *msg)
{
        return strlen(msg);
}
 
int test_char(const char *msg)
{
        return strlen(msg);
}
Personal tools
Namespaces
Variants
Actions
Navigation
Browse
Toolbox