2

I am thinking about the right side (expansion) of a function like macro. Consider this example:

#define addOneTo(a)    (a)++

Would do the job. But then I came across to a compound statements to be expressed via macros like this one:

#define addOneTo(a,b)    (a)++; (b)++

Will do the job too. But if I want to use the macro in this occasion:

if(true)
   addOneTo(a,b);

I would get:

if(true)
   (a)++; (b)++;

In ^^this^^ case b will be incremented no-matter the value of the expression in the if statement. And this is not what I want. Therefore I googled it, and came across to this solution:

#define addOneTo(a,b)    do{ (a)++; (b)++;  }while(0)

So I am happy with the example ^^above^^, except I don't understand the do while(0), cant we just use compound statement like this???:

#define addOneTo(a,b)    { (a)++; (b)++;  }     

What is the motivation behind this implementation?

Hairi
  • 3,318
  • 2
  • 29
  • 68
  • I wouldn't have come up with it alone. It is very subtle, but the solution is brilliant. – Hairi Feb 28 '17 at 15:18
  • 1
    The do/while trick forces the programmer to append a semicolon. This makes code look syntactically ok. A mere block in curlies does not have this property. – Jens Feb 28 '17 at 15:28
  • And the essential part is that it doesn't brake the `if-else` construct – Hairi Feb 28 '17 at 15:31
  • Never use macro where a function will do! Any reason you don't want your compiler help checking your program for type-correctness, etc.? And something like `addOneTo(a++, b++)` will inkoke undefined behaviour. – too honest for this site Feb 28 '17 at 15:31
  • @Olaf In an embedded 8-bit micro with very limited resources, a function call is reasonable overhead. Imagine you call that function that only increases one value 1000 times in your code. This approach saves processor's time – Hairi Feb 28 '17 at 15:33
  • 2
    @Hairi: Sorry, but that is nonsense! Unless you use an antique compiler, an `inline` function will perform as well, but without all the problems a macro adds (see my edited comment ^). Don't do premature optimisations at the cost of code maintainability and readbility. Compilers have advanced a lot the last 20 years. – too honest for this site Feb 28 '17 at 15:34
  • @Olaf Will `inline` function allocate space in the stack for its params? – Hairi Feb 28 '17 at 15:37
  • @Hairi The point of an inline function (if it really gets inlined) is that there is no call, so no argument space is needed. The called function's body is just inserted at the call site, just like with a macro but with the added protection of actually being a function. – unwind Feb 28 '17 at 15:39
  • @Olaf, then it is OK. What do you mean with "(if it really gets inlined)"? – Hairi Feb 28 '17 at 15:41
  • @Hairi: The C standard does not require using a stack. Please first try this, read what `inline` functions are, how they are compiled, look at some example code generated by your toolchain, profile your code. And **only** if that fails, even think about macros. Don't get stuck with prejudice from the last century about compiler capabilities. It is very likely the compiler will generate much better code than you can. – too honest for this site Feb 28 '17 at 15:42
  • 1
    The solution is simple: 1) don't be Apple and always use `{ }` after every single conditional statement. 2) avoid function-like macros whenever possible. The function-like macros in your examples are pure nonsense and greatly reduces the readability of the program, while at the same time introducing a great potential for bugs. Don't write such crappy code. Don't try to replace the C language with your own secret, garage-hacker macro language. – Lundin Feb 28 '17 at 15:42
  • @Hairi Regarding "function call is overhead", welcome to the 1990s! We have function inlining now. Simply don't use compilers from the 80s and you should be good. You don't even need to use the `inline` keyword, that's a thing of the late 90s. – Lundin Feb 28 '17 at 15:43
  • @Hairi: Last comment from me about this pointless discussion: Just give up on controlling every byte of output and counting bits. Concentrate on the **function** first! If you can't, forget about C, go back to the 1980ies MCU programming and write assembly code. There are good **macro**-assemblers available. – too honest for this site Feb 28 '17 at 15:46
  • The goal of the macros was purely to represent the problem. I haven't pretended to to be meaningful, it is not their purpose. Regarding the macros, I think you guys have a point! I am confused of the statement of @Lundin "You don't even need to use the inline keyword". How come? – Hairi Feb 28 '17 at 15:50
  • @Olaf This discussion is not pointless. This is giving me a know-how not easy to find elsewhere. – Hairi Feb 28 '17 at 15:52
  • 1
    @Hairi Because modern optimizing compilers are nowadays smarter than the programmer when it comes to determining when a function should be inlined or not. In the 90s there were concerns that excessive inlining would lead to bloated program size and therefore the programmer was supposed to determine this, as a way to manually optimize either for speed or for program size. Program size is less of an issue nowadays, and the inline keyword in C99/C11 is mostly a recommendation from the programmer to the compiler. The compiler is still free to inline code with/without the presence of the keyword. – Lundin Mar 01 '17 at 08:28

0 Answers0