15

In a previous question what I thought was a good answer was voted down for the suggested use of macros

#define radian2degree(a) (a * 57.295779513082)
#define degree2radian(a) (a * 0.017453292519)

instead of inline functions. Please excuse the newbie question, but what is so evil about macros in this case?

Community
  • 1
  • 1
semaj
  • 1,555
  • 1
  • 12
  • 25
  • 9
    In this case, degree2radian(45 + a / 2.0) doesn't do what you thought. Always parenthesize every argument in the expansion - well, almost always; the main exceptions are when you're doing things like token pasting or stringizing. – Jonathan Leffler Oct 28 '09 at 22:01
  • 3
    what Jonathan says - one thing worse than seeing a macro definition that's a pain in the ass to read because of all the damn parens, is coming across a macro definition that doesn't have all those damn parens. – Michael Burr Oct 29 '09 at 00:11
  • 3
    There's also the ALLCAPS convention for macros, which at least puts them into their own pseudo-namespace. – David Thornley Oct 29 '09 at 13:42

8 Answers8

8

For this specific macro, if I use it as follows:

int x=1;
x = radian2degree(x);
float y=1;
y = radian2degree(y);

there would be no type checking, and x,y will contain different values.

Furthermore, the following code

float x=1, y=2;
float z = radian2degree(x+y);

will not do what you think, since it will translate to

float z = x+y*0.017453292519;

instead of

float z = (x+y)+0.017453292519;

which is the expected result.

These are just a few examples for the misbehavior ans misuse macros might have.

Edit

you can see additional discussions about this here

Community
  • 1
  • 1
Amirshk
  • 8,170
  • 2
  • 35
  • 64
  • 3
    Good answer. It's also worth mentioning namespace pollution (e.g. that I can no longer declare a local variable or struct field named `radian2degree`). – Pavel Minaev Oct 28 '09 at 21:56
  • I don't understand your first complaint. x will not be transformed to floating-point by the macro, but by the multiplication. – David Thornley Oct 28 '09 at 22:10
  • 1
    my point was both uses are valid and will compile, but you won't see any indication for this. your macro _should_ accept only floating points number, but it will accept anything. – Amirshk Oct 28 '09 at 22:15
  • @Jonathan, nice touch. not only it won't compile, it's really hard to see the reason. – Amirshk Oct 28 '09 at 22:21
  • enforcing interfaces is the reason why you MUST use inline functions (even if macros are evil in general...but sometimes it's nice) – LB40 Oct 28 '09 at 22:55
  • Also, you're using these macros as if they modify their arguments. They don't. At the end of the day, both `x` and `y` will be 1 in your examples, because the macro return values are being thrown away. – Chris Lutz Oct 29 '09 at 00:11
  • @Chris, fixed. the theoretical bug still exists. – Amirshk Oct 29 '09 at 00:30
  • I've cleaned up the code so it only contains valid fragments. – Jonathan Leffler Oct 29 '09 at 00:39
  • I still don't understand your first complaint. In what way is the macro behavior different from the function? In both cases, the int will be coerced to a double, a double value created, and forced back into an int. – David Thornley Oct 29 '09 at 13:42
  • @David, if you will define an inline function, you will declare a type to be received. Say float, if the developer would pass int instead, the compiler will warn on this. In the macro situation it won't. – Amirshk Oct 29 '09 at 15:05
8

Most of the other answers discuss why macros are evil including how your example has a common macro use flaw. Here's Stroustrup's take: http://www.research.att.com/~bs/bs_faq2.html#macro

But your question was asking what macros are still good for. There are some things where macros are better than inline functions, and that's where you're doing things that simply can't be done with inline functions, such as:

  • token pasting
  • dealing with line numbers or such (as for creating error messages in assert())
  • dealing with things that aren't expressions (for example how many implementations of offsetof() use using a type name to create a cast operation)
  • the macro to get a count of array elements (can't do it with a function, as the array name decays to a pointer too easily)
  • creating 'type polymorphic' function-like things in C where templates aren't available

But with a language that has inline functions, the more common uses of macros shouldn't be necessary. I'm even reluctant to use macros when I'm dealing with a C compiler that doesn't support inline functions. And I try not to use them to create type-agnostic functions if at all possible (creating several functions with a type indicator as a part of the name instead).

I've also moved to using enums for named numeric constants instead of #define.

Michael Burr
  • 333,147
  • 50
  • 533
  • 760
  • An other useful case for macros is for initialization of objects in the data segment: int global = radian2degree(2*PI); – calandoa Oct 29 '09 at 18:32
  • Yup - I rarely deal with floating point numbers myself, so I typically use enums now instead of macros for named numeric constants. But clearly that can't be done for floats like `PI`, so a macro it would be. – Michael Burr Oct 29 '09 at 19:22
  • On compilers with gcc extensions, macros, unlike inline functions, can test whether their arguments can be evaluated as constants. If one wishes to have a "function" like `reverse8bits(x)` which computes a bit-reversed byte value, it may be best to use `(((x&128)>>7)|((x&64)>>5)...)` when `x` is a constant (in which case the nasty-looking expression yields a constant) but call a library routine when `x` is a variable. I wish `C` allowed inline functions to be overloaded based upon whether arguments were compile-time constants, since that would be cleaner, and... – supercat Oct 12 '12 at 16:50
  • ...the naming-related problems with allowing function overloading in C (which are, from what I understand, the reason standards people have as yet decided not to allow such overloads) wouldn't apply to inline or static functions (since compilers have always been free to name such functions however they see fit, provided only that declaration of same-named functions in different modules doesn't cause a naming conflict at link time). – supercat Oct 12 '12 at 16:53
7

There's a couple of strictly evil things about macros.

They're text processing, and aren't scoped. If you #define foo 1, then any subsequent use of foo as an identifier will fail. This can lead to odd compilation errors and hard-to-find runtime bugs.

They don't take arguments in the normal sense. You can write a function that will take two int values and return the maximum, because the arguments will be evaluated once and the values used thereafter. You can't write a macro to do that, because it will evaluate at least one argument twice, and fail with something like max(x++, --y).

There's also common pitfalls. It's hard to get multiple statements right in them, and they require a lot of possibly superfluous parentheses.

In your case, you need parentheses:

#define radian2degree(a) (a * 57.295779513082)

needs to be

#define radian2degree(a) ((a) * 57.295779513082)

and you're still stepping on anybody who writes a function radian2degree in some inner scope, confident that that definition will work in its own scope.

David Thornley
  • 56,304
  • 9
  • 91
  • 158
  • 2
    I always find the statements of "feature 'x' is evil don't ever use it" seem to imply that programmers are immensely stupid. Recommend that macros be named in a way which identifies themselves as macros when used: RADIAN2DEGREEmac or similar. – James Morris Oct 29 '09 at 10:47
  • 5
    "Feature X is evil" doesn't mean "don't use feature X", and I didn't quite say macros were evil in themselves. The all-caps convention is valuable, but doesn't solve all the problems. Same with the strict parenthesizing and the other tricks. I'd recommend avoiding function-like macros if possible, because there's usually better ways to do whatever you're trying to do. – David Thornley Oct 29 '09 at 13:39
  • 1
    @David Good answer but it didn't answer the question: "When should you use macros instead of inline functions?" It seems like you answered the opposite: why you shouldn't use macros. But when is it "better" to use a macro instead of a function? – styfle Sep 01 '11 at 16:45
  • @styfle: The question in the main body was "what is so evil about macros in this case?", and I answered that one. I missed the one in the question title, admittedly. – David Thornley Sep 01 '11 at 17:11
  • @David: I am interested in the title. Although I found my answer: certain things you can only do with Macros since C doesn't have templates like C++. – styfle Sep 01 '11 at 20:52
  • @James "_I always find the statements of "feature 'x' is evil don't ever use it" seem to imply ..._". I'm ordinarily in agreement. I'm certainly very wary of absolutes like "don't ever use it". That said, I've often seen the other side of the coin where "experienced" developers take the stance: "I'm an _expert_, so it's ok to break the rules" ... meanwhile, back at the ranch, they've implemented something completely unnecessary, and very dangerous. While I don't like labelling people "stupid"; clearly the "experienced" developer erred out of ignorance. A harsher warning may induce 2nd thought. – Disillusioned Dec 05 '17 at 10:43
2

if possible, always use inline function. These are typesafe and can not be easily redefined.

defines can be redfined undefined, and there is no type checking.

RED SOFT ADAIR
  • 12,032
  • 10
  • 54
  • 92
  • 1
    The downside in C (as opposed to C++) is that not all compilers necessarily support them - or default to a mode where they are supported. They were added in C99, but some compilers (MSVC, for example) are not C99 compliant. I don't know whether MSVC supports this bit of the standard - it might because it also has C++ support lurking around. However, it does not have other C99 features that would be very nice to have. – Jonathan Leffler Oct 28 '09 at 22:04
  • 2
    A smart compiler will ignore the `inline` directive and inline or not as the individual call indicates. – David Thornley Oct 28 '09 at 22:08
  • @David +1, inline is a pure recommendation. – LB40 Oct 28 '09 at 22:56
  • MSCV supports inline functions in C mode using the `__inline` extension. – Michael Burr Oct 29 '09 at 00:26
2

Macros are relatively often abused and one can easily make mistakes using them as shown by your example. Take the expression radian2degree(1 + 1):

  • with the macro it will expand to 1 + 1 * 57.29... = 58.29...
  • with a function it will be what you want it to be, namely (1 + 1) * 57.29... = ...

More generally, macros are evil because they look like functions so they trick you into using them just like functions but they have subtle rules of their own. In this case, the correct way would be to write it would be (notice the paranthesis around a):

#define radian2degree(a) ((a) * 57.295779513082)

But you should stick to inline functions. See these links from the C++ FAQ Lite for more examples of evil macros and their subtleties:

Catalin Iacob
  • 644
  • 5
  • 18
  • 1
    +1 but a) macros aren't "evil in general." They can be abused, but they're not the root of all evil, any more than `goto`s are. b) Why link to the C++ FAQ for a C question? There is no C++ tag, and no C++-specific information in the question. – Chris Lutz Oct 29 '09 at 00:13
  • You're right about "evil in general", it was too harsh and general. I edited it. Related to b), as far as I see all the information in the C++ FAQ links that I gave also applies to C and I think the problems/subtleties of macros are clearly explained there so I see them as valuable links for this question. So why not link to the C++ FAQ? – Catalin Iacob Oct 29 '09 at 08:36
1

The compiler's preprocessor is a finnicky thing, and therefore a terrible candidate for clever tricks. As others have pointed out, it's easy to for the compiler to misunderstand your intention with the macro, and it's easy for you to misunderstand what the macro will actually do, but most importantly, you can't step into macros in the debugger!

ajs410
  • 2,384
  • 2
  • 19
  • 14
0

Macros are evil because you may end up passing more than a variable or a scalar to it and this could resolve in an unwanted behavior (define a max macro to determine max between a and b but pass a++ and b++ to the macro and see what happens).

Percutio
  • 979
  • 7
  • 8
0

If your function is going to be inlined anyway, there is no performance difference between a function and a macro. However, there are several usability differences between a function and a macro, all of which favor using a function.

If you build the macro correctly, there is no problem. But if you use a function, the compiler will do it correctly for you every time. So using a function makes it harder to write bad code.

Daniel Pryden
  • 59,486
  • 16
  • 97
  • 135