Macro vs Function in C

2019-01-02 22:09发布

I always saw examples and cases where using a macro is better than using function.

Could someone explain me with an example the disadvantage of a macro compared to a function?

10条回答
smile是对你的礼貌
2楼-- · 2019-01-02 23:00

Side-effects are a big one. Here's a typical case:

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

min(x++, y)

gets expanded to:

(x++ < y ? x++ : y)

x gets incremented twice in the same statement. (and undefined behavior)


Writing multi-line macros are also a pain:

#define foo(a,b,c)  \
    a += 10;        \
    b += 10;        \
    c += 10;

They require a \ at the end of each line.


Macros can't "return" anything unless you make it a single expression:

int foo(int *a, int *b){
    side_effect0();
    side_effect1();
    return a[0] + b[0];
}

Can't do that in a macro unless you use GCC's expression statement. (EDIT: You can use a comma operator though... overlooked that... But it might still be less readable.)


Order of Operations: (courtesy of @ouah)

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

min(x & 0xFF, 42)

gets expanded to:

(x & 0xFF < 42 ? x & 0xFF : 42)

But & has lower precedence than <. So 0xFF < 42 gets evaluated first.

查看更多
Evening l夕情丶
3楼-- · 2019-01-02 23:02

Macros are error-prone because they rely on textual substitution and do not perform type-checking. For example, this macro:

#define square(a) a * a

works fine when used with an integer:

square(5) --> 5 * 5 --> 25

but does very strange things when used with expressions:

square(1 + 2) --> 1 + 2 * 1 + 2 --> 1 + 2 + 2 --> 5
square(x++) --> x++ * x++ --> increments x twice

Putting parentheses around arguments helps but doesn't completely eliminate these problems.

When macros contain multiple statements, you can get in trouble with control-flow constructs:

#define swap(x, y) t = x; x = y; y = t;

if (x < y) swap(x, y); -->
if (x < y) t = x; x = y; y = t; --> if (x < y) { t = x; } x = y; y = t;

The usual strategy for fixing this is to put the statements inside a "do { ... } while (0)" loop.

If you have two structures that happen to contain a field with the same name but different semantics, the same macro might work on both, with strange results:

struct shirt 
{
    int numButtons;
};

struct webpage 
{
    int numButtons;
};

#define num_button_holes(shirt)  ((shirt).numButtons * 4)

struct webpage page;
page.numButtons = 2;
num_button_holes(page) -> 8

Finally, macros can be difficult to debug, producing weird syntax errors or runtime errors that you have to expand to understand (e.g. with gcc -E), because debuggers cannot step through macros, as in this example:

#define print(x, y)  printf(x y)  /* accidentally forgot comma */
print("foo %s", "bar") /* prints "foo %sbar" */

Inline functions and constants help to avoid many of these problems with macros, but aren't always applicable. Where macros are deliberately used to specify polymorphic behavior, unintentional polymorphism may be difficult to avoid. C++ has a number of features such as templates to help create complex polymorphic constructs in a typesafe way without the use of macros; see Stroustrup's The C++ Programming Language for details.

查看更多
Juvenile、少年°
4楼-- · 2019-01-02 23:04

one drawback to macros is that debuggers read source code, which does not have expanded macros, so running a debugger in a macro is not necessarily useful. Needless to say, you cannot set a breakpoint inside a macro like you can with functions.

查看更多
贼婆χ
5楼-- · 2019-01-02 23:04

Functions do type checking. This gives you an extra layer of safety.

查看更多
登录 后发表回答