Why are C macros not type-safe?

后端 未结 7 1658
礼貌的吻别
礼貌的吻别 2021-02-18 16:01

If have encountered this claim multiple times and can\'t figure out what it is supposed to mean. Since the resulting code is compiled using a regular C compiler it will end up b

相关标签:
7条回答
  • 2021-02-18 16:12

    When the macro runs, it just does a text match through your source files. This is before any compilation, so it is not aware of the datatypes of anything it changes.

    0 讨论(0)
  • 2021-02-18 16:13

    There are situations where macros are even less type-safe than functions. E.g.

    void printlog(int iter, double obj)
    {
        printf("%.3f at iteration %d\n", obj, iteration);
    }
    

    Calling this with the arguments reversed will cause truncation and erroneous results, but nothing dangerous. By contrast,

    #define PRINTLOG(iter, obj) printf("%.3f at iteration %d\n", obj, iter)
    

    causes undefined behavior. To be fair, GCC warns about the latter, but not about the former, but that's because it knows printf -- for other varargs functions, the results are potentially disastrous.

    0 讨论(0)
  • 2021-02-18 16:18

    Macros aren't type safe, because they were never meant to be type safe.

    The compiler does the type checking after macros had been expanded.

    Macros and there expansion are meant as a helper to the ("lazy") author (in the sense of writer/reader) of C source code. That's all.

    0 讨论(0)
  • 2021-02-18 16:18

    Macros aren't type safe because they don't understand types.

    You can't tell a macro to only take integers. The preprocessor recognises a macro usage and it replaces one sequence of tokens (the macro with its arguments) with another set of tokens. This is a powerful facility if used correctly, but it's easy to use incorrectly.

    With a function you can define a function void f(int, int) and the compiler will flag if you try to use the return value of f or pass it strings.

    With a macro - no chance. The only checks that get made are it is given the correct number of arguments. then it replaces the tokens appropriately and passes onto the compiler.

    #define F(A, B)
    

    will allow you to call F(1, 2), or F("A", 2) or F(1, (2, 3, 4)) or ...

    You might get an error from the compiler, or you might not, if something within the macro requires some sort of type safety. But that's not down to the preprocessor.

    You can get some very odd results when passing strings to macros that expect numbers, as the chances are you'll end up using string addresses as numbers without a squeak from the compiler.

    0 讨论(0)
  • 2021-02-18 16:20

    Well they're not directly type-safe... I suppose in certain scenarios/usages you could argue they can be indirectly (i.e. resulting code) type-safe. But you could certainly create a macro intended for integers and pass it strings... the pre-processor handling the macros certainly doesn't care. The compiler may choke on it, depending on usage...

    0 讨论(0)
  • 2021-02-18 16:26

    Consider the typical "max" macro, versus function:

    #define MAX(a,b) a < b ? a : b
    int max(int a, int b) {return a < b ? a : b;}
    

    Here's what people mean when they say the macro is not type-safe in the way the function is:

    If a caller of the function writes

    char *foo = max("abc","def");
    

    the compiler will warn.

    Whereas, if a caller of the macro writes:

    char *foo = MAX("abc", "def");
    

    the preprocessor will replace that with:

    char *foo = "abc" < "def" ? "abc" : "def";
    

    which will compile with no problems, but almost certainly not give the result you wanted.

    Additionally of course the side effects are different, consider the function case:

    int x = 1, y = 2;
    int a = max(x++,y++); 
    

    the max() function will operate on the original values of x and y and the post-increments will take effect after the function returns.

    In the macro case:

    int x = 1, y = 2;
    int b = MAX(x++,y++);
    

    that second line is preprocessed to give:

    int b = x++ < y++ ? x++ : y++;
    

    Again, no compiler warnings or errors but will not be the behaviour you expected.

    0 讨论(0)
提交回复
热议问题