7
votes
\$\begingroup\$

Which one of the following is preferrable and why when writing C macro?

Type 1

#define I2C_START()                 I2C_WAIT_IDLE(); SSP1CON2bits.SEN  = 1

Type 2

#define I2C_START()               \
    do                            \
    {                             \
        I2C_WAIT_IDLE();          \
        SSP1CON2bits.SEN  = 1;    \
    }while(0)

One of my colleagues prefers Type 1 while I prefer Type 2. So when both of us work in a project, both of the types are seen throughout the project.

\$\endgroup\$
2
  • \$\begingroup\$ c-faq.com/cpp/multistmt.html explains it in detail. \$\endgroup\$
    – Alok
    Apr 16, 2011 at 4:20
  • 1
    \$\begingroup\$ This question appears to be off-topic because it is about best practice regarding a specific language feature. See help center. \$\endgroup\$ Feb 8, 2014 at 17:28

4 Answers 4

15
votes
\$\begingroup\$

I prefer the second one because it can be used with normal compound stamens without modifications or accidentally being used incorrectly.

if (condition)
    I2c_START;  

Type 1: FAIL
Type 2: OK

Of course with good coding standards that can be avoided (always use '{' '}' on if). But every now and then people can be lazy (or just careless) and the second version prevents accidents from happening.

The best solution is not to use macros. Use functions and let the compiler work out when to inline.

Edited:

For billy: (Type 3) no do while

#define I2C_START()   \
{                             \
    I2C_WAIT_IDLE();          \
    SSP1CON2bits.SEN  = 1;    \
}

Unfortunately this fails if you use the else part of the if statement:
The trailing semi-colon (on type 3) marks the end of the if statement thus else is not syntactically allowed. At least this gives you a compilation error unlike above. But Type 2 still works as expected.

if (condition)
    I2C_START();
else
    std::cout << "FAIL this test\n";

Type 1: FAIL
Type 2: OK
Type 3: FAIL

\$\endgroup\$
6
  • \$\begingroup\$ Well, you really don't need the "do" and "while (0)" bits for type 2 to prevent this though. A plain block will do just fine. \$\endgroup\$ Apr 7, 2011 at 4:23
  • 1
    \$\begingroup\$ It's syntax thing. Having only {} block will expand to if (...) { ... }; and spare ; is not good. \$\endgroup\$
    – blaze
    Apr 7, 2011 at 7:17
  • \$\begingroup\$ @blaze, really? You're worried about a semicolon that only the compiler will see, and ignore? \$\endgroup\$
    – AShelly
    Apr 9, 2011 at 1:54
  • 6
    \$\begingroup\$ @AShelly: if (foo) do { bar; } while 0; else { mmm; } = ok. if (foo) {bar} ; else {mmm;} = syntax error on else, because spare ; terminated if-statement. Oops :) \$\endgroup\$
    – blaze
    Apr 11, 2011 at 10:01
  • \$\begingroup\$ Ok, good point. \$\endgroup\$
    – AShelly
    Apr 11, 2011 at 19:09
6
votes
\$\begingroup\$

The Linux Kernel Newbies FAQ has an entry on this, since Linux uses it extensively. It's the syntax-safe way of defining these kinds of macros.

\$\endgroup\$
2
  • \$\begingroup\$ It would be good if you could actually put the content in your answer. \$\endgroup\$ Jun 22, 2013 at 9:30
  • \$\begingroup\$ It's a long FAQ entry, sorry. \$\endgroup\$ Jul 2, 2013 at 2:19
4
votes
\$\begingroup\$

The second form is the safest without having to think too much about the consequences way.

but for what you are using it for? neither really need to be used. It should be a function. I'm taking it this is PIC code.... the overhead of the function call won't cost you that much.

\$\endgroup\$
1
  • \$\begingroup\$ yes it is pic. we typically write macros for 2/3 lines of register access. \$\endgroup\$
    – Donotalo
    Apr 8, 2011 at 11:42
0
votes
\$\begingroup\$

I something similar to type two but without the do while as in:

#define I2C_START()               \
do                            \
{                             \
    I2C_WAIT_IDLE();          \
    SSP1CON2bits.SEN  = 1;    \
}while(0)

The do while could be difficult to understand for an inexperienced coder. I also always use {} even for onliner if statements.

\$\endgroup\$
2
  • \$\begingroup\$ any inexperience coder should learn what do{}while(0) does. \$\endgroup\$
    – Donotalo
    May 5, 2011 at 12:22
  • \$\begingroup\$ Yes. But by keeping it obvious and simple you avoid problems with people that have not or do not want to learn. \$\endgroup\$
    – Gerhard
    May 6, 2011 at 5:39

Not the answer you're looking for? Browse other questions tagged or ask your own question.