Just to make sure I have it right on macros - Page 1
Forum section: electronics / general

author: Simon
author_rank: Unknown
timestamp: October 16, 2015, 05:46:52 pm
content: 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.

author: Kalvin
author_rank: Super Contributor
timestamp: October 16, 2015, 06:04:17 pm
content: 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 thewhile (0).As a general rule, you should always use the "do { } while (0)" wrapper when you have multiple statements in the macro.

author: newbrain
author_rank: Super Contributor
timestamp: October 16, 2015, 06:24:26 pm
content: 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:#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.

author: Simon
author_rank: Unknown
timestamp: October 16, 2015, 06:35:36 pm
content: 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.

author: Kalvin
author_rank: Super Contributor
timestamp: October 16, 2015, 06:45:56 pm
content: Quote from: Simon on October 16, 2015, 06:35:36 pmIf 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.

author: Simon
author_rank: Unknown
timestamp: October 16, 2015, 06:51:04 pm
content: You mean i have to remember how i wrote my macro so thatif (expression)macroactually needs writing asif (expression) {macro}

author: Kalvin
author_rank: Super Contributor
timestamp: October 16, 2015, 06:55:20 pm
content: Quote from: Simon on October 16, 2015, 06:51:04 pmYes, 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.

author: newbrain
author_rank: Super Contributor
timestamp: October 16, 2015, 07:01:53 pm
content: Quote from: Simon on October 16, 2015, 06:51:04 pmExactly: if you use the do..while (0) (no semicolon) and the function syntax youdon'thave 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.

author: langwadt
author_rank: Super Contributor
timestamp: October 16, 2015, 10:35:48 pm
content: http://hackaday.com/2015/10/16/code-craft-when-define-is-considered-harmful/

author: Hypernova
author_rank: Unknown
timestamp: October 17, 2015, 05:30:56 am
content: Just the { } brackets would have worked. No need for do while(0) that might confuse people.

author: rolfe
author_rank: Newbie
timestamp: October 17, 2015, 05:52:24 am
content: Quote from: Hypernova on October 17, 2015, 05:30:56 amNo, { } 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.

author: Hypernova
author_rank: Unknown
timestamp: October 17, 2015, 06:41:59 am
content: Quote from: rolfe on October 17, 2015, 05:52:24 amThe 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.

author: Ian.M
author_rank: Super Contributor
timestamp: October 17, 2015, 06:53:26 am
content: 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.

author: Simon
author_rank: Unknown
timestamp: October 17, 2015, 07:43:40 am
content: I'm using atmel studio with CGG compiler, non of that microchip crippleware

author: mikerj
author_rank: Super Contributor
timestamp: October 17, 2015, 08:05:30 am
content: Quote from: Hypernova on October 17, 2015, 06:41:59 amConsider what will happen when the macro is used in an if-else construct:Code:if (some expression)your_macro();elsemyfunction();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.

author: Hypernova
author_rank: Unknown
timestamp: October 17, 2015, 10:50:33 am
content: Quote from: mikerj on October 17, 2015, 08:05:30 amPoint 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 likehttps://www.imperialviolet.org/2014/02/22/applebug.html

author: mikerj
author_rank: Super Contributor
timestamp: October 17, 2015, 10:55:57 am
content: Quote from: Hypernova on October 17, 2015, 10:50:33 amRight, 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?