A basic C-question

Go To Last Post
9 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi there.
I have seen several posters using macro definitions like:

reset_timeout() do { TCNT1 = 0; } while (0) 

What is the actual benefit with the do{} while (0) construction?

Regards

Olof

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The do while construction will always execute the related code at least once, since the test is made at the end of the block.

Four legs good, two legs bad, three legs stable.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Why not make TCNT1 = 0 only ?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You have to expand your example to actually notice the benefit. So e.g. (bad)

#define reset_timeout() TCNT1 = 0; tresets++

vs. (good)

#define reset_timeout() do { TCNT1 = 0; treset++; } while(0)

Both defines leave out a semicolon to give the usage a resonable function like appearence:

reset_timeout();

But notice the difference with the two versions in this context:

if (someFlag)
    reset_timeout();

It will not work as expected with the bad definition ( TCNT1 = 0 is executed when someFlag is true but treset++) is always executed.

The do while version also introduces a block that that can be useful for local variables for use in the macro.

Edit: Just need to add that tricks like this are becomming a thing of the past, just use inline functions.

/Lars

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

As far as I can tell

#define reset_timeout() {TCNT=0; tresets++;}

has the same features. The do{}while(0) is not needed. Am I missing something?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Ah but consider:

if (cond) 
  reset_timeout();
else
 something_else();

If reset_timeout was defined as you suggest this would expand to:

if (cond) {
  TCNT=0;
  tresets++;
}
;
else
 something_else();

The semi colon would terminate the if () and the else would be left "floating" whereas:

if (cond) do {
  TCNT=0;
  tresets++;
} while(0);
else
 something_else();

would circumvent this "spare semi-colon" problem.

Cliff

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Two remarks:

> The do while construction will always execute the related code at
> least once, since the test is made at the end of the block.

Not "at least once" (not in our context), but "exactly once".

> Just need to add that tricks like this are becomming a thing of the
> past, just use inline functions.

It depends. First, inline functions are a C99 feature, while macros
are portable across any C compiler. Second, "inline" is a *hint* to
the compiler, not a requirement. Even GCC might occasionally get the
idea the function to be inlined might become too complex, and won't
inline it. (Use __attribute__((always_inline)) to avoid that,
together with the "inline" keyword.) Finally, a preprocessor macro
can take arguments (and can do nasty things on arguments, like
concetaneting or stringifying them) which an inline function cannot
do.

Jörg Wunsch

Please don't send me PMs, use email if you want to approach me personally.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks for your clarifications.
My conclusion is that the do {}while(0) is pointless (in a flow control perspective) if it only contains a single C-statment but that it is needed if I write a macro that contains several statments and if that macro shall be "programmer safe" for use in a if-else context. It can be a point to use the do{single-C-statement;}while(0) to indicate how future expansion of the macro should be done since it is likely that the macro normaly is used in flow control.

Olof

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I've just modified one of my projects to use safe macros as stated above (I forgot when programming to do it but i've avoided all the cases where it would be a problem so far). My solution to "neaten things up" was to define:

#define MACROS                   do
#define MACROE                   while (0)

So I could then use macros like:

#define OSCCAL_SETSYSCLOCKSPEED(x) 	MACROS{ CLKPR = (1 << CLKPCE); CLKPR = x; }MACROE

I like the preprocessor! This method protects your macros while maintaining readability. Also note that i've ommitted the trailing end-of-line semicolon from after the "while (0)" so that you can use the psudo-functions in a functon-like manner:

OSCCAL_SETSYSCLOCKSPEED(0);

- Dean :twisted:

Make Atmel Studio better with my free extensions. Open source and feedback welcome!