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\$
  • \$\begingroup\$ c-faq.com/cpp/multistmt.html explains it in detail. \$\endgroup\$ – Alok Apr 16 '11 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\$ – 200_success Feb 8 '14 at 17:28
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\$
  • \$\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\$ – Billy ONeal Apr 7 '11 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 '11 at 7:17
  • \$\begingroup\$ @blaze, really? You're worried about a semicolon that only the compiler will see, and ignore? \$\endgroup\$ – AShelly Apr 9 '11 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 '11 at 10:01
  • \$\begingroup\$ Ok, good point. \$\endgroup\$ – AShelly Apr 11 '11 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\$
  • \$\begingroup\$ It would be good if you could actually put the content in your answer. \$\endgroup\$ – Lyndon White Jun 22 '13 at 9:30
  • \$\begingroup\$ It's a long FAQ entry, sorry. \$\endgroup\$ – The UNIX Man Jul 2 '13 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\$
  • \$\begingroup\$ yes it is pic. we typically write macros for 2/3 lines of register access. \$\endgroup\$ – Donotalo Apr 8 '11 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\$
  • \$\begingroup\$ any inexperience coder should learn what do{}while(0) does. \$\endgroup\$ – Donotalo May 5 '11 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 '11 at 5:39

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