Author Topic: Just to make sure I have it right on macros  (Read 4939 times)

0 Members and 1 Guest are viewing this topic.

Offline SimonTopic starter

  • Global Moderator
  • *****
  • Posts: 17816
  • Country: gb
  • Did that just blow up? No? might work after all !!
    • Simon's Electronics
Just to make sure I have it right on macros
« on: October 16, 2015, 05:46:52 pm »
Just to confirm I read my theory correctly before I write hundreds of lines of code:

#define counter1_mode0 bit0(TCCR1B, WGM13); bit0(TCCR1B, WGM12); bit0(TCCR1A, WGM11); bit0(TCCR1A, WGM10);

Is correct right? As you can probably tell I'm writing macros to enable me to sleep set up my microcontroller. I'm not going Arduino style but it is tedious to keep researching the register names scrolling up and down to find which bit name goes in which register name (very in mind a potential for attention deficit disorder) so I figured that I can write a bunch of macros which tally to the datasheet so mode one for counter one is easy to cross-reference from the datasheet to my list of macros and it says me so much typing.
 

Offline Kalvin

  • Super Contributor
  • ***
  • Posts: 2145
  • Country: fi
  • Embedded SW/HW.
Re: Just to make sure I have it right on macros
« Reply #1 on: October 16, 2015, 06:04:17 pm »
Safer way is to use the "do { } while (0)" wrapper:

#define counter1_mode0 do { bit0(TCCR1B, WGM13); bit0(TCCR1B, WGM12); bit0(TCCR1A, WGM11); bit0(TCCR1A, WGM10); } while (0)

Note: There is no semicolon after the while (0).

As a general rule, you should always use the "do { } while (0)" wrapper when you have multiple statements in the macro.
« Last Edit: October 16, 2015, 06:23:49 pm by Kalvin »
 

Online newbrain

  • Super Contributor
  • ***
  • Posts: 1719
  • Country: se
Re: Just to make sure I have it right on macros
« Reply #2 on: October 16, 2015, 06:24:26 pm »
To Kalvin's sound advice I would add that if the macro performs an action (rather than being an alias for a value) it's better to give it an argument list.
In this way, the C function syntax is preserved.


Code: [Select]
#define counter1_mode0() do { bit0(TCCR1B, WGM13); bit0(TCCR1B, WGM12); bit0(TCCR1A, WGM11); bit0(TCCR1A, WGM10); } while (0)
The arg list is empty in our case.
Nandemo wa shiranai wa yo, shitteru koto dake.
 

Offline SimonTopic starter

  • Global Moderator
  • *****
  • Posts: 17816
  • Country: gb
  • Did that just blow up? No? might work after all !!
    • Simon's Electronics
Re: Just to make sure I have it right on macros
« Reply #3 on: October 16, 2015, 06:35:36 pm »
ok thank you.

Does any of this matter much though ? I'm confused about why I have a do/while when if I was wringting it into my program I'd not have to.
 

Offline Kalvin

  • Super Contributor
  • ***
  • Posts: 2145
  • Country: fi
  • Embedded SW/HW.
Re: Just to make sure I have it right on macros
« Reply #4 on: October 16, 2015, 06:45:56 pm »
ok thank you.

Does any of this matter much though ? I'm confused about why I have a do/while when if I was wringting it into my program I'd not have to.

If you write the code just for yourself, it doesn't matter. But using the do/while-wrapper the macro can be used as an ordinary statement, so it is considered as a good programming practice.

For example, you can use the macro in the if-statement without problems:

if (some expression)
   your_macro();


as the macro will be expanded as follows:

if (some expression)
   do {
       stmt1;
       stmt2;
       stmt3;
   } while 0;


But, without the do/while-wrapper the result will be quite different:

if (some expression)
    stmt1;
stmt2;
stmt3;


which is not what you intended, but it will compile without any problems, though.
 

Offline SimonTopic starter

  • Global Moderator
  • *****
  • Posts: 17816
  • Country: gb
  • Did that just blow up? No? might work after all !!
    • Simon's Electronics
Re: Just to make sure I have it right on macros
« Reply #5 on: October 16, 2015, 06:51:04 pm »
You mean i have to remember how i wrote my macro so that

if (expression)
macro

actually needs writing as

if (expression) {
macro
}
 

Offline Kalvin

  • Super Contributor
  • ***
  • Posts: 2145
  • Country: fi
  • Embedded SW/HW.
Re: Just to make sure I have it right on macros
« Reply #6 on: October 16, 2015, 06:55:20 pm »
You mean i have to remember how i wrote my macro so that

if (expression)
macro

actually needs writing as

if (expression) {
macro
}

Yes, that is one example. But like I said earlier, if you write the code only for yourself, it doesn't really matter. But if your code is intended to be part of a project with multiple programmers, I would consider using the do/while-wrapper as a mandatory rule.
 

Online newbrain

  • Super Contributor
  • ***
  • Posts: 1719
  • Country: se
Re: Just to make sure I have it right on macros
« Reply #7 on: October 16, 2015, 07:01:53 pm »
You mean i have to remember how i wrote my macro so that

if (expression)
macro

actually needs writing as

if (expression) {
macro
}

Exactly: if you use the do..while (0) (no semicolon) and the function syntax you don't have to remember!
And maybe, in a month time, you'll change from a macro to a real function (or the other way round...) and you won't need to rearrange braces and semicolons, or you'll use it again and you won't need to check whether it's a macro or function.
Nandemo wa shiranai wa yo, shitteru koto dake.
 

Online langwadt

  • Super Contributor
  • ***
  • Posts: 4425
  • Country: dk
 

Offline Hypernova

  • Supporter
  • ****
  • Posts: 655
  • Country: tw
Re: Just to make sure I have it right on macros
« Reply #9 on: October 17, 2015, 05:30:56 am »
Just the { } brackets would have worked. No need for do while(0) that might confuse people.
 

Offline rolfe

  • Newbie
  • Posts: 6
  • Country: au
  • "This is me"
Re: Just to make sure I have it right on macros
« Reply #10 on: October 17, 2015, 05:52:24 am »
Just the { } brackets would have worked. No need for do while(0) that might confuse people.

No, { } won't work. If you put a semi-colon after the macro call you end up with two statements, which is not what you want.

Really, you're almost certainly better off using an inline function. You'll get all the benefits of type checking, scoping, and no surprising macro expansion gotchas. These days compilers will generate just the same code.
 

Offline Hypernova

  • Supporter
  • ****
  • Posts: 655
  • Country: tw
Re: Just to make sure I have it right on macros
« Reply #11 on: October 17, 2015, 06:41:59 am »
Just the { } brackets would have worked. No need for do while(0) that might confuse people.

No, { } won't work. If you put a semi-colon after the macro call you end up with two statements, which is not what you want.

Really, you're almost certainly better off using an inline function. You'll get all the benefits of type checking, scoping, and no surprising macro expansion gotchas. These days compilers will generate just the same code.

The additional statement contains no operations and evaluations so gets compiled to nothing no? Problem with inline property is that with some compilers if optimizations are not enabled to a certain point the compiler ignores the statement. Macros due to being just text replacement commands are often the only way to ensure certain programme behaviors.
 

Online Ian.M

  • Super Contributor
  • ***
  • Posts: 12860
Re: Just to make sure I have it right on macros
« Reply #12 on: October 17, 2015, 06:53:26 am »
The do{ ... }while(0) wrapper *usually* is optimised away by the compiler. However some crappy compilers (or ones with deliberately crippled optimisation) may actually generate the never taken jump to the do, and skip over it. [:(]

If all the statements in the macro can be evaluated as expressions returning something other than void, they can alternatively be spliced together by the comma operator and wrapped in () brackets. 
 

Offline SimonTopic starter

  • Global Moderator
  • *****
  • Posts: 17816
  • Country: gb
  • Did that just blow up? No? might work after all !!
    • Simon's Electronics
Re: Just to make sure I have it right on macros
« Reply #13 on: October 17, 2015, 07:43:40 am »
I'm using atmel studio with CGG compiler, non of that microchip crippleware
 

Offline mikerj

  • Super Contributor
  • ***
  • Posts: 3240
  • Country: gb
Re: Just to make sure I have it right on macros
« Reply #14 on: October 17, 2015, 08:05:30 am »
The additional statement contains no operations and evaluations so gets compiled to nothing no?

Consider what will happen when the macro is used in an if-else construct:

Code: [Select]
if (some expression)
   your_macro();
else
   myfunction();

If you just have braces around the macro, the semicolon terminates the true part of the if statement which leaves the else part orphaned.  This means the code won't even compile, but would work fine using the do{}while(0) method.
 

Offline Hypernova

  • Supporter
  • ****
  • Posts: 655
  • Country: tw
Re: Just to make sure I have it right on macros
« Reply #15 on: October 17, 2015, 10:50:33 am »
The additional statement contains no operations and evaluations so gets compiled to nothing no?

Consider what will happen when the macro is used in an if-else construct:

Code: [Select]
if (some expression)
   your_macro();
else
   myfunction();

If you just have braces around the macro, the semicolon terminates the true part of the if statement which leaves the else part orphaned.  This means the code won't even compile, but would work fine using the do{}while(0) method.


Point taken, but this problem only manifest if you are not in the habit of bracketing if/else which is poor coding practice that leads to mess like https://www.imperialviolet.org/2014/02/22/applebug.html
 

Offline mikerj

  • Super Contributor
  • ***
  • Posts: 3240
  • Country: gb
Re: Just to make sure I have it right on macros
« Reply #16 on: October 17, 2015, 10:55:57 am »
The additional statement contains no operations and evaluations so gets compiled to nothing no?

Consider what will happen when the macro is used in an if-else construct:

Code: [Select]
if (some expression)
   your_macro();
else
   myfunction();

If you just have braces around the macro, the semicolon terminates the true part of the if statement which leaves the else part orphaned.  This means the code won't even compile, but would work fine using the do{}while(0) method.


Point taken, but this problem only manifest if you are not in the habit of bracketing if/else which is poor coding practice that leads to mess like https://www.imperialviolet.org/2014/02/22/applebug.html

Right, but you don't know what someone else is going to do in the future so it's a bug waiting to happen.  The do{}while(0) is a very simple universal fix with no overhead (on any reasonable compiler) so why not use it?
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf