Are C macros implicitly cast?

2019-01-25 18:44发布

问题:

I've searched SO, but haven't found an answer to this specific questions. Forgive me if it's already been answered.

If you have the following:

#define MACRO  40

You don't assign it to a variable you use it in a loop:

for(int i = 0; i < MACRO; i++) {...

The perprocessor then creates:

for(int i = 0; i < 40; i++) {...

Would the compiler then implicitly cast it to an int since the comparison is with type int i? I've looked at this question Type of #define variables, and quite a few answers down Edgar Bonet implies that there is an order in which the compiler chooses how to treat the macro?

This question, How does C++ implicitly cast arguments to a comparator such as <?, was also suggested, but only describes how implicit casting works with a comparison with two types. Since a macro doesn't really have a type I'm not sure if this applies.

回答1:

The preprocessor expands macros before the compiler even sees anything. We can see that preprocessing numbers don't have a type by going to the draft C99 standard section 6.4.8 Preprocessing numbers which says:

A preprocessing number does not have type or a value; it acquires both after a successful conversion (as part of translation phase 7) to a floating constant token or an integer constant token.

The same section in the draft C++ standard is 2.10.

As we can see in C preprocessor Wikipedia article macro expansion happens in phase 4.

The conversion of integer constants in C terminology and integer literals in C++ terminology is covered in the draft C99 standard section 6.4.4.1 Integer constants and the following table in paragraph 5 which says:

The type of an integer constant is the first of the corresponding list in which its value can be represented

                                           Octal or Hexadecimal
Suffix        Decimal Constant                 Constant
---------------------------------------------------------------------------
none          int                           int
              long int                      unsigned int
              long long int                 long int                                
                                            unsigned long int
                                            long long int
                                            unsigned long long int
---------------------------------------------------------------------------
u or U        unsigned int                  unsigned int
              unsigned long int             unsigned long int
              unsigned long long int        unsigned long long int
---------------------------------------------------------------------------
l or L        long int                      long int
              long long int                 unsigned long int
                                            long long int
                                            unsigned long long int
---------------------------------------------------------------------------
Both u or U   unsigned long int             unsigned long int
and  l or L   unsigned long long int        unsigned long long int
---------------------------------------------------------------------------
ll or LL      long long int                 long long int
                                            unsigend long long int
---------------------------------------------------------------------------
Both u or U   unsigned long long int        unsigned long long int
and  ll or LL
---------------------------------------------------------------------------

Table is a modified version of the one from this answer. The section that covers this in the draft C++ standard is section 2.14.2 which also has a similar table.

So in your example 40 has no suffix and is a decimal constant and the first type it can be represented from that section of the table is int.

At this point we now end up with the effects of using 40 with the < operator. Since i and 40 are both arithmetic types then the usual arithmetic conversions will be performed, which in this case will still be int. For C99 this is covered in section 6.3.1.8 and C++ section 5.



回答2:

In C and C++, macros are quite literally in-place replacement. The preprocessor will encounter these #defines and replace them as it finds them. That's how you can nest macros inside of macros and it only takes 1 pass to preprocess.



回答3:

C macros are simply textual replacements, they have no types. Everything involving types is done after the macro substitution, and acts the same as if you'd typed the replacement in the original code.



回答4:

The compiler never sees the macro; the preprocessor expands all macros before the source text is fed into the compiler.

All the compiler sees is

for(int i = 0; i < 40; i++) {...}

and the type of the constant expression 40 is determined based on the rules in section 6.4.4.1 of the 2011 C standard or section 2.13 of the online C++ standard.



回答5:

In C macros are just replacement text that means that the text the macro represents is copied instead of the macro name, you can put even C keywords in macro.

#define [identifier name] [value]

In the code the identifier name is replace by the value. Your definition was:

#define MACRO  40

40 is already an int. so for(int i = 0; i < 40; i++) no cast is required.