C++ 中的宏和 const 有什么区别?
我在一次技术面试中被问到这个问题:
C++ 中的
const
和宏有什么区别?
我的答案是,宏是一个预处理器指令,如果使用宏,则调试应用程序可能会很困难,因为它在编译之前被替换为常量表达式,而 const
可以具有类型标识符并且易于调试。
有人能指出任何其他区别以及应该优先选择哪个吗?
编辑:
来自 IBM C++ 文档:
以下是
#define
和const
类型限定符之间的一些区别:
< /里>
#define
指令可用于创建数字、字符或字符串常量的名称,而可以声明任何类型的 const 对象。const 对象受变量作用域规则的约束,而使用
#define
创建的常量则不然。与 const 对象不同,宏的值不会出现在编译器使用的中间源代码中,因为它们是内联扩展的。内联扩展使宏值对调试器不可用。宏可以在常量表达式中使用,例如数组绑定,而
const
对象则不能。 (我认为我们肯定需要使用宏来定义array_size
。编译器不会对宏(包括宏参数)进行类型检查。
I was asked this question in a technical interview:
What is the difference between a
const
and a macro in C++?
My answer was that a macro is a preprocessor directive and it could be difficult to debug the application if you use a macro since it is replaced with the constant expression before compilation, whereas a const
can have a type identifier and is easy to debug.
Could anyone point out any other difference and which should be preferred?
EDIT:
From the IBM documentation for C++:
The following are some differences between
#define
and theconst
type qualifier:
The
#define
directive can be used to create a name for a numerical, character, or string constant, whereas a const object of any type can be declared.A const object is subject to the scoping rules for variables, whereas a constant created using
#define
is not. Unlike aconst
object, the value of a macro does not appear in the intermediate source code used by the compiler because they are expanded inline. The inline expansion makes the macro value unavailable to the debugger.A macro can be used in a constant expression, such as an array bound, whereas a
const
object cannot. (I think we surely need to use macro to definearray_size
.The compiler does not type-check a macro, including macro arguments.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(7)
宏和常量完全不是一回事,它们有时都适合具体情况,而您的答案仅触及差异的表面。此外,C++ 有两种不同类型的常量。
使用
const
限定符定义的常量最好被视为不可修改的变量。它具有变量的所有属性:它有类型,有大小,有链接,你可以获取它的地址。 (如果编译器能够摆脱这些属性,它可能会优化其中一些属性:例如,地址从未使用过的常量可能不会被发送到可执行映像中。但这只是由于 as-if 规则的恩典。 ) 对 const 数据唯一不能做的就是改变它的值。用enum
定义的常量有点不同。它有类型和大小,但它没有链接,你无法获取它的地址,而且它的类型是唯一的。这两个值都是在翻译阶段 7 期间处理的,因此它们只能是左值或右值。 (我对前一句中的行话感到抱歉,但否则我将不得不写几段。)宏的约束要少得多:它可以扩展到任何标记序列,只要整个程序保持良好-形成的程序。它不具有变量的任何属性。将
sizeof
或&
应用于宏可能会也可能不会做一些有用的事情,具体取决于宏扩展的内容。宏有时被定义为扩展为数字文字,并且此类宏有时被认为为常量,但它们不是:“编译器本身”(即翻译阶段 7)将它们视为 < em>数字文字。如今,当常量就可以时,不要使用宏,这通常被认为是良好的做法。宏不遵循与所有其他标识符相同的作用域规则,这可能会令人困惑,如果您使用常量,您将为翻译阶段 7 提供更多信息,从而也为调试器提供更多信息。然而,宏允许您做一些其他方式无法完成的事情,如果您需要做其中一件事情,您应该毫不犹豫地使用它们。 (从这个意义上说,发挥作用的宏通常不只是扩展到数字文字,尽管我不会说永远不会。)
编辑:这是一个例子宏做一些有趣的事情。它绝不是一个常数。很可能有一种方法可以在不使用宏的情况下获得相同的效果(如果您知道不涉及字符串流的方法,我很想听听它!)但我认为它很好地说明了功能和功能宏的危险(对于后者,考虑如果在一个非常特定的上下文之外使用它会做什么......)
Macros and constants are not remotely the same thing, each is sometimes appropriate for the circumstances, and your answer only scratches at the surface of the difference. Also, C++ has two different kinds of constants.
A constant defined with the
const
qualifier is best thought of as an unmodifiable variable. It has all the properties of a variable: it has a type, it has a size, it has linkage, you can take its address. (The compiler might optimize away some of these properties if it can get away with it: for instance, constants whose address is never used may not get emitted into the executable image. But this is only by the grace of the as-if rule.) The only thing you can't do to aconst
datum is change its value. A constant defined withenum
is a little different. It has a type and a size, but it doesn't have linkage, you can't take its address, and its type is unique. Both of these are processed during translation phase 7, so they can't be anything but an lvalue or rvalue. (I'm sorry about the jargon in the preceding sentence, but I would have to write several paragraphs otherwise.)A macro has far fewer constraints: it can expand to any sequence of tokens, as long as the overall program remains a well-formed program. It doesn't have any of the properties of a variable. Applying
sizeof
or&
to a macro may or may not do something useful, depending on what the macro expands to. Macros are sometimes defined to expand to numeric literals, and such macros are sometimes thought of as constants, but they're not: "the compiler proper" (that is, translation phase 7) sees them as numeric literals.It is generally considered good practice, nowadays, not to use a macro when a constant will do. Macros don't obey the same scoping rules as all other identifiers, which can be confusing, and if you use a constant you give more information to translation phase 7 and thus also to the debugger. However, macros permit you to do things that cannot be done any other way, and if you need to do one of those things, you should not hesitate to use them. (Macros that are pulling their weight, in this sense, generally do not just expand to numeric literals, though I am not going to say never.)
EDIT: Here's an example of a macro doing something interesting. It is in no way, shape or form a constant. There may well be a way to get the same effect without a macro (if you know one that doesn't involve stringstreams, I'd be curious to hear about it!) but I think it makes a good illustration of both the power and the danger of macros (for the latter, consider what it would do if it was used outside of one very specific context...)
出于多种原因,人们应该更喜欢
const int sum = 1;
而不是#define sum 1
:基于范围的机制:
#define 不尊重作用域,因此无法创建类作用域的命名空间。虽然 const 变量的作用域可以在类中。
在编译错误期间避免奇怪的魔法数字:
如果您使用
#define
,这些数字会在预编译时被预处理器替换所以如果您在编译过程中收到错误,这会令人困惑,因为错误消息不会引用宏名称,而是引用值,并且它会突然出现一个值,并且会浪费大量时间在代码中跟踪它。易于调试:
同样出于同样的原因,在调试
#define
时实际上不会提供任何帮助。为了避免上述两种情况,
const
将是更好的选择。One should prefer
const int sum = 1;
over#define sum 1
for a number of reasons:Scope Based Mechanism:
#define
s don't respect scopes so there is no way to create a class scoped namespace. While const variables can be scoped in classes.Avoiding Weird magical numbers during compilation errors:
If you are using
#define
those are replaced by the pre-processor at time of precompilation So if you receive an error during compilation, it will be confusing because the error message wont refer the macro name but the value and it will appear a sudden value, and one would waste lot of time tracking it down in code.Ease of Debugging:
Also for same reasons, while debugging
#define
would provide no help really.To avoid both above situations
const
will be a better choice.(最初发布于 static const vs #define - 在这里复制,因为这个问题似乎有更多的“动力”...让我知道这是否不合适...)
一切的优点和缺点,取决于用法:
#define
ala#define S std::string("abc")
,但该常量可以避免重复构造不同的临时变量在每个使用点#define X "x"
和一些客户端使用 ala"pre" X "post"
,如果您想要或需要,您就会遇到麻烦使 X 成为运行时可更改的变量而不是常量,而从const char*
或const std::string
进行转换会更容易,因为它们已经强制用户合并串联操作。{ 1, 2 }
,或#define MICROSECONDS *1E-6
等(绝对不推荐这个!)__FILE__
和__LINE__
可以合并到宏替换中templatevoid f(T t) { cout << ++t; }
无法编译)templatevoid f(T)
当从不同的枚举传递相同的数值时,会得到一个不同的实例化,所有这些都与任何实际的 f(int) 实例化不同。作为一般规则,我使用 const 并认为它们是最专业的选择一般用法(尽管其他用法的简单性吸引了这个老懒程序员)。
( 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:
#define
ala#define S std::string("abc")
, but the constant avoids repeated construction of distinct temporaries at each point of use#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 aconst char*
orconst std::string
given they already force the user to incorporate concatenation operations.{ 1, 2 }
that can be used to initialise arrays, or#define MICROSECONDS *1E-6
etc. (definitely not recommending this!)__FILE__
and__LINE__
can be incorporated into the macro substitutiontemplate <typename T> void f(T t) { cout << ++t; }
won't compile)template <typename T> 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.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).
另一个区别是 const 变量具有内存并且可以由指针引用。宏只是编译前发生的自动完成,因此名称在编译期间丢失。
宏也可以不仅仅是一个常数。它可以是 am 表达式或任何语法正确的东西,甚至是函数的完整定义。
宏用于描述编程选择,例如堆栈大小;而
cosnt
用于描述现实世界的常数,例如Pi或e的值。Another difference is that a
const
variable has a memory and can be referenced by a pointer. Macro is just the autocomplete that will happen before compilation, hence the name is lost during compiling.Also macro can be just more than a constant. It can be am expression or anything that is syntactically correct, even a whole definition of a function.
Macros are used to depict programming choices e.g. stack size; while
cosnt
is used to depict the real world constants like value of Pi or e.Define 可以重新定义,但 const 会导致编译错误:
示例:
来源:main.cpp
define can be redefine , but const will be cause compiler error:
sample:
source : main.cpp
宏不考虑范围,并且符号调试器可能无法使用宏的名称。 Dan Saks 有一篇相当完整的文章,介绍了宏(无)、常量对象和枚举常量的相对优点。与 Stephen Dewhurst 一样,Saks 更喜欢整数值的枚举常量,因为它们不占用存储空间(更准确地说,枚举常量既没有存储期限也没有链接)。
Macros don't respect scope, and a macro's name may not be available to a symbolic debugger. Dan Saks has a fairly complete article on the relative merits of macros (none), constant objects, and enumeration constants. Like Stephen Dewhurst, Saks prefers enumeration constants for integer values since they take up no storage (more precisely, enumeration constants have neither storage duration nor linkage).
宏总是有一个类型,例如,
#define FIVE 5
是 int 类型。const 变量相对于宏的一个优点是内存使用量:对于宏,可能必须在使用它的所有地方重复该值,这样 const 变量就不会在内存中重复。 (但我不确定这个区别)
A macro always have a type, for instance,
#define FIVE 5
is of type int.An advantage for the const variable over the macro could be the memory usage : With a macro the value may have to be duplicated everywhere it is used will a const variable will not be duplicated in memory. (but I am not sure of this difference)