Why are C macros not type-safe?

2020-06-30 05:26发布

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 being type checked just as much (or little) as any other code.

So why are macros not type safe? It seems to be one of the major reasons why they should be considered evil.

标签: c++ c types macros
7条回答
Luminary・发光体
2楼-- · 2020-06-30 05:47

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.

查看更多
甜甜的少女心
3楼-- · 2020-06-30 05:49

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.

查看更多
姐就是有狂的资本
4楼-- · 2020-06-30 05:52

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...

查看更多
相关推荐>>
5楼-- · 2020-06-30 05:54

Since macros are handled by the preprocessor, and the preprocessor doesn't understand types, it will happily accept variables that are of the wrong type.

This is usually only a concern for function-like macros, and any type errors will often be caught by the compiler even if the preprocessor doesn't, but this isn't guaranteed.

An example

In the Windows API, if you wanted to show a balloon tip on an edit control, you'd use Edit_ShowBalloonTip. Edit_ShowBalloonTip is defined as taking two parameters: the handle to the edit control and a pointer to an EDITBALLOONTIP structure. However, Edit_ShowBalloonTip(hwnd, peditballoontip); is actually a macro that evaluates to

SendMessage(hwnd, EM_SHOWBALLOONTIP, 0, (LPARAM)(peditballoontip));

Since configuring controls is generally done by sending messages to them, Edit_ShowBalloonTip has to do a typecast in its implementation, but since it's a macro rather than an inline function, it can't do any type checking in its peditballoontip parameter.

A digression

Interestingly enough, sometimes C++ inline functions are a bit too type-safe. Consider the standard C MAX macro

#define MAX(a, b) ((a) > (b) ? (a) : (b))

and its C++ inline version

template<typename T>
inline T max(T a, T b) { return a > b ? a : b; }

MAX(1, 2u) will work as expected, but max(1, 2u) will not. (Since 1 and 2u are different types, max can't be instantiated on both of them.)

This isn't really an argument for using macros in most cases (they're still evil), but it's an interesting result of C and C++'s type safety.

查看更多
等我变得足够好
6楼-- · 2020-06-30 06:01

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.

查看更多
家丑人穷心不美
7楼-- · 2020-06-30 06:07

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.

查看更多
登录 后发表回答