
How to properly use macros in C - pmihaylov
http://pmihaylov.com/macros-in-c/
======
cjensen
If you're going to write a long lecture to people, it's helpful to do some
Googling to fact-check your own understanding.

The claim that macros do not exist in other languages is incorrect. Every
sensible assembly language compiler has macros to help the programmer with
boilerplate.

The claim that multiline macros are a problem is correct. Suggesting that a
workaround is to use a naming convention for such macros is crazy-talk. There
is a time-honored pattern you use to fix this in the macro itself: wrap the
macro with "do { <macro content> } while (0)".

~~~
bluetomcat
The goal of this article is not to provide some genuine insight to the topic,
but to serve as a publicity stunt for the largest code academy in Bulgaria,
dubiously called "Software University". On numerous other occasions their
lecturers and trainers have made ridiculously misleading claims about trivial
programming stuff. One of their lecturers insisted that the second return in
"return; return;" was probably needed just in case the first one did not work:

[https://www.youtube.com/watch?v=_ZwiMlyeQNU&t=15s](https://www.youtube.com/watch?v=_ZwiMlyeQNU&t=15s)

In short, kids with little to no programming experience teach other
disorientated desperate kids with few career opportunities in a country with a
primitive economy.

~~~
Stratoscope
Well, I'm sorry, but I agree with the lecturer. I've run into this problem
myself.

In my case I had some cleanup code to run at the end of the function in an
error case, so I used "goto fail;" instead of "return;". And then just to be
sure it _always_ worked, I put in the "goto fail;" twice!

~~~
mkroman
Spotted the Apple developer!

------
ecma
This isn't wrong but I've got issues with some of the examples, especially the
lack of a solution for #2 and #4.

#2 is referred to as an unsafe macro because of the multiple evaluation of its
arguments. In some cases this is fine but it may need to be documented that
the macro is unsafe for future users. It is also entirely possible to convert
these macros into safe ones if you're willing/able to use GNU C extensions
like typeof. The SEI CERT secure C wiki has a good reference for this at [0].

#3 presumes you want to compose functions but I'd suggest that by doing so you
are writing bad C. Because of the lack of any type of side-band error
reporting (exceptions etc) you must presume that your functions will always
return a sane/non-error value. That's not a good assumption even for your own
code and definitely not for the C library or any other libs. In addition, this
is just another unsafe macro which could be made safe as above.

#4 doesn't explain the solution to the problem it poses which is annoying
because it's the most important one IMO. There are a number of ways to make a
multi-line macro safe for use in an unbraced expression body. My preferred way
is to define the macro with a always false-post check while loop. e.g.

    
    
        #define MY_NAME_JEF(x) do{ \
            const char jef[] = "jef"; \
            printf("my name %s, not %s\n", jef, x); \
        }while(0)
    

Note the lack of a trailing semi-colon. This is because we expect the macro to
be terminated with its own semi-colon. Stupid example but it gets the point
across I suppose.

Check out the secure C wiki, it's full of gems which can help you avoid issues
with macros, and much more.

[0]
[https://wiki.sei.cmu.edu/confluence/display/c/PRE31-C.+Avoid...](https://wiki.sei.cmu.edu/confluence/display/c/PRE31-C.+Avoid+side+effects+in+arguments+to+unsafe+macros)

~~~
Stratoscope
> #2 is referred to as an unsafe macro because of the multiple evaluation of
> its arguments. In some cases this is fine but it may need to be documented
> that the macro is unsafe for future users.

In the early days of C programming, a naming convention was adopted to warn
about this. If you wrote a macro that might have multiple evaluation of its
arguments, you named it in UPPERCASE as a warning:

    
    
        #define MIN( a, b )  ( (a) < (b) ? (a) : (b) )
    

This practice spread into pretty much all macro definitions. If you defined a
macro of any sort, you gave it an uppercase name, even if the macro didn't
take any arguments at all and therefore warning about multiple evaluation was
moot:

    
    
        #define MAX_SIGNED_SHORT 32767
    

From there the notion spread into other languages that _all_ constants ought
to have UPPER_CASE_NAMES. So this is why you see JavaScript code like:

    
    
        const TEMP_ITEM_LIMIT = 100;
    

instead of something easier on the eyes like:

    
    
        const tempItemLimit = 100;

~~~
photonios
Although I get that the original intent was different. I actually find making
all constants uppercase a useful practice. When reading the code, it's easy to
see what is a local variable and what is not, or at least not supposed to be.

------
phoe-krk

        One strange phenomenon when coding in C is using macros. This is not something which can be seen in other programming languages (other than C++).
    

This is false. Lisp is a language, or rather, a family of languages, where
macros play a giant role, and the author does not seem to mention them.

But again, Lisps generally have more powerful macros than C does - they allow
for arbitrary compile-time computation.

~~~
Stratoscope
More readable quote:

> _One strange phenomenon when coding in C is using macros. This is not
> something which can be seen in other programming languages (other than
> C++)._

Instead of indenting a quote, use:

    
    
      > The quote.
    

or if you want italics to set it off more:

    
    
      > *The quote.*

~~~
phoe-krk
Thanks, TIL.

------
jeff571
The article is an okay start, but it wasn't written by an expert. It lists
some real pitfalls but doesn't provide commonly accepted solutions. Some
examples...

multiple lines: wrap in do { } while (0) \- can use a multiline macro like a
function call, terminated with ; or ({foo; bar;}) \- multiple lines evaluate
to 'bar'...

Function calls: \- in general anything with side effects could be harmful if
evaluated more than once. \- But possible to write MIN()/MAX() with single
evaluation of 'a' and 'b'. #define MAX(a, b) \ ({typeof(a) _a = (a); typeof(b)
_b = (b); _a > _b ? _a : _b;})

And other important things like stringify, variadics, etc...

~~~
colanderman
({ }) is handy but is a GCC extension.

So is "typeof"; "__typeof__" is the standard spelling.

~~~
AstralStorm
Which is why C++ has decltype that is standard now.

------
vortico
The golden rule of macros is "always read the definition of macros before
using." If you know it's a single value you're probably fine `#define MASK
0xf7`, but if it's a function macro or a normal macro that you know is doing
more than inserting a literal in your code, it's best to glance at the macro
to see what it does. Macros are useful for writing "shorthand C", but C should
not be turned into a DSL, so you should _think_ in actual C by converting the
"shorthand C" in your head as you read/write it.

------
loup-vaillant
> _macros can’t be debugged. When you use a function, that function can be
> stepped through by the debugger. The macro cannot._

Looks like the debugger could use some improvement.

> _A macro is faster than a function._

This is false. Macros may be faster in some cases, but I've seen them being
_slower_. I suspect this is because functions have more type information that
can help the optimiser. I've tried it with Monocypher: replacing
serialisation/de-serialisation functions (load and store) by equivalent macros
slowed the whole thing down.

~~~
manwe150
> Looks like the debugger could use some improvement.

Try `gcc -g3` (the default is 2). But because C-style macros are context-
sensative string operations, the result is not necessarily especially
pleasant/useful and can be rather large (slowing down the debugger for
everything else).

I find that using `static inline` functions and `static const` variables in
the header can just be much nicer to work with all around (some argument type-
checking, better stack frame management means alloca is usable, no accidental
syntax clashes requiring lots of extra parens to avoid, and real debug info).
And, if necessary, use a tiny macro just to form the call to the real function
or form the declarations for repeated tabular data. I wouldn't have expected
macros to be slower in any case, however.

~~~
loup-vaillant
> _I wouldn 't have expected macros to be slower in any case, however._

Neither did I to be honest. I was searching for low hanging fruits, and
forcing inlining with macros looked made some kind of sense. I expected the
compiler to generate the same code, yet somehow it didn't.

------
unwind
Calling all C preprocessor directives (like #include and #if) "macros" makes
me skeptical. Is this usage common?

~~~
vortico
You are correct, this usage is wrong. They are "preprocessor directives", and
macros are only what come after #define.

~~~
jwilk
To be pedantically correct: the C standards call them "preprocess _ing_
directives".

------
bluetomcat
An article that is an outspring of the hugely-overhyped IT industry in Sofia
(Bulgaria). Code academies, recruitment agencies, startup organisations and
conference organisers are literally larger than the entire IT sector and they
all want to make a quick buck from desperate young people with very limited
choices for a prospective career in other fields.

"We will make you a rich programmer in 3 months", they say.

------
rocqua
> When you add the inline keyword in front of a function, you are hinting the
> compiler to embed the function body inside the caller (just like a macro).

That is not quite the case. The inline keyword has changed to mean multiple
definitions are allowed. To quote [1]: " Because the meaning of the keyword
inline for functions came to mean 'multiple definitions are permitted' rather
than 'inlining is preferred' "

[1]
[http://en.cppreference.com/w/cpp/language/inline](http://en.cppreference.com/w/cpp/language/inline)

------
kkmx
The problem with those explanations is that they are pointless. Unless you're
still in college taking a C course, most people understand that macros are
substitutions.

------
bluetomcat
Let's write pointless articles because reading basic programming books has
become so unfashionable.

------
tomsmeding
> Some compilers offer debug strings in macros, which cannot be used in
> functions: __FILE__, __LINE__, __func__.

But... Of course they can. They are just symbols defined by the compiler, and
have nothing to do with being in a macro expansion or not. Heck, they are
probably implemented as macro's themselves inside the preprocessor.

~~~
jstimpfle
What he means is, you want to use them in a macro. You can't get the effect
you probably want by using them in a function. Compare:

    
    
        #define LOG_ERROR() printf("ERROR at %s:%d\n", __FILE__, __LINE__)
        void logError(void) { printf("ERROR at %s:%d\n", __FILE__, __LINE__); }

~~~
tomsmeding
Sure, they are pretty useless in a function. But that doesn't mean that the
author can go and use incorrect language. :P

~~~
AstralStorm
Except when they work properly when fully inlined. (Sprinkle GCC/Clang magic
here. It is required to make it work.)

~~~
tomsmeding
Is that even possible? It shouldn't be without extensions. (But that seems to
be what you're implying anyway.)

------
jstewartmobile
Sometimes it is easier to just "look before you leap":

    
    
      gcc -E myprogram.c

------
Fronzie
answer: you don't

~~~
vortico
There are many valid use cases of macros in C (and other languages) which you
might not have seen, like those which use __LINE__ etc, those which expand a
string into a variable type or function, those which process `-DNAME=x` flags.

------
bligh____
An intro to C macros ? Is this reddit ? What happened to hn ?

~~~
jwilk
From the HN guidelines:

 _Please don 't complain that a submission is inappropriate. If a story is
spam or off-topic, flag it._

