What is the difference between a macro and a const in C++?

前端 未结 7 1655
长情又很酷
长情又很酷 2020-12-01 02:08

I was asked this question in a technical interview:

What is the difference between a const and a macro in C++?

My a

7条回答
  •  粉色の甜心
    2020-12-01 02:54

    ( Originally posted for static const vs #define - reproducing here as this question seems to have more "momentum"... let me know if that's inappropriate... )

    Pros and cons to everything, depending on usage:

    • consts
      • properly scoped / identifier clash issues handled nicely
      • strong, single, user-specified type
        • you might try to "type" a #define ala #define S std::string("abc"), but the constant avoids repeated construction of distinct temporaries at each point of use
      • One Definition Rule complications
      • can take address, create const references to them etc.
    • defines
      • "global" scope / more prone to conflicting usages, which can produce hard-to-resolve compilation issues and unexpected run-time results rather than sane error messages; mitigating this requires:
        • long, obscure and/or centrally coordinated identifiers, and access to them can't benefit from implicitly matching used/current/Koenig-looked-up namespace, namespace aliases etc.
        • use of all uppercase characters is generally required and reserved for preprocessor defines (an important guideline for enterprise scale preprocessor usage to remain manageable, and which 3rd party libraries can be expected to follow), observation of which implies migration of existing consts or enums to defines involves a change in capitalisation (and hence affects client code). (Personally, I capitalise the first letter of enums but not consts, so I'd be hit here anyway - maybe time to rethink that.)
      • more compile-time operations possible: string literal concatenation, stringification (taking size thereof)
        • downside is that given #define X "x" and some client usage ala "pre" X "post", you're in trouble if you want or need to make X a runtime-changeable variable rather than a constant, whereas that transition is easier from a const char* or const std::string given they already force the user to incorporate concatenation operations.
      • can't use sizeof directly on a defined numeric constant
      • untyped (GCC doesn't warn if compared to unsigned)
      • some compiler/linker/debugger chains may not present the identifier, so you'll be reduced to looking at "magic numbers" (strings, whatever...)
      • can't take the address
      • the substituted value need not be legal (or discrete) in the context where the #define is created, as it's evaluated at each point of use, so you can reference not-yet-declared objects, depend on "implementation" that needn't be pre-included, create "constants" such as { 1, 2 } that can be used to initialise arrays, or #define MICROSECONDS *1E-6 etc. (definitely not recommending this!)
      • some special things like __FILE__ and __LINE__ can be incorporated into the macro substitution
    • enums
      • only possible for integer values
      • properly scoped / identifier clash issues handled nicely
      • strongly typed, but to a big-enough signed-or-unsigned int size over which you have no control (in C++03)
      • can't take the address
      • stronger usage restraints (e.g. incrementing - template void f(T t) { cout << ++t; } won't compile)
      • each constant's type taken from the enclosing enum, so template void f(T) get a distinct instantiation when passed the same numeric value from different enums, all of which are distinct from any actual f(int) instantiation.
      • even with typeof, can't expect numeric_limits to provide useful insight
      • the enum's typename may appear in various places in RTTI, compiler messages etc. - possibly useful, possibly obfuscation

    As a general rule, I use consts and consider them the most professional option for general usage (though the others have a simplicity appealing to this old lazy programmer).

提交回复
热议问题