“静态常量”与“#define”相比与“枚举”
下面的 C 语言语句中,哪一个更好用?
static const int var = 5;
或
#define var 5
或
enum { var = 5 };
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(17)
这取决于您需要什么价值。您(以及到目前为止的其他人)省略了第三种选择:
static const int var = 5;
#define var 5
enum { var = 5 };
code>忽略有关名称选择的问题,那么:
因此,在大多数情况下,更喜欢“枚举”而不是其他选择。否则,第一个和最后一个要点很可能是控制因素——如果你需要同时满足这两个要点,你就必须更加努力地思考。
如果您询问有关 C++ 的问题,那么您每次都会使用选项 (1) - static const。
It depends on what you need the value for. You (and everyone else so far) omitted the third alternative:
static const int var = 5;
#define var 5
enum { var = 5 };
Ignoring issues about the choice of name, then:
So, in most contexts, prefer the 'enum' over the alternatives. Otherwise, the first and last bullet points are likely to be the controlling factors — and you have to think harder if you need to satisfy both at once.
If you were asking about C++, then you'd use option (1) — the static const — every time.
一般来说:
因为它尊重范围并且是类型安全的。
我能看到的唯一警告:如果您希望变量可能在命令行上定义。还有一个替代方案:
只要有可能,就使用类型安全的替代方案来代替宏/省略号。
如果您确实需要使用宏(例如,您想要
__FILE__
或__LINE__
),那么您最好非常仔细地命名您的宏:在其 命名约定 Boost 建议全部大写,以项目名称开头(此处为 BOOST_),在仔细阅读库时,您会注意到(通常)后面跟着特定的名称区域(图书馆),然后用一个有意义的名称。它通常会导致名字很长:)
Generally speaking:
Because it respects scope and is type-safe.
The only caveat I could see: if you want the variable to be possibly defined on the command line. There is still an alternative:
Whenever possible, instead of macros / ellipsis, use a type-safe alternative.
If you really NEED to go with a macro (for example, you want
__FILE__
or__LINE__
), then you'd better name your macro VERY carefully: in its naming convention Boost recommends all upper-case, beginning by the name of the project (here BOOST_), while perusing the library you will notice this is (generally) followed by the name of the particular area (library) then with a meaningful name.It generally makes for lengthy names :)
具体来说,在C语言中?在 C 中,正确的答案是:使用
#define
(或者,如果合适,使用enum
)。虽然拥有
const< 的作用域和类型属性是有益的/code> 对象,实际上 C(与 C++ 相对)中的
const
对象不是真正的常量,因此在大多数实际情况下通常是无用的。因此,在 C 中,选择应该取决于您计划如何使用常量。例如,您不能使用
const int
对象作为case
标签(但宏可以使用)。您不能使用const int
对象作为位字段宽度(尽管宏可以工作)。在 C89/90 中,您不能使用 const 对象来指定数组大小(而宏可以工作)。即使在 C99 中,当您需要非 const 对象来指定数组大小rel="noreferrer">VLA 数组。如果这对您很重要,那么它将决定您的选择。大多数时候,您别无选择,只能在 C 中使用
#define
。并且不要忘记另一种选择,它可以在 C 中生成真正的常量 -enum
。在 C++ 中,
const
对象是真正的常量,因此在 C++ 中,最好选择const
变体(在 C++ 中不需要显式的static
)尽管)。In C, specifically? In C the correct answer is: use
#define
(or, if appropriate,enum
)While it is beneficial to have the scoping and typing properties of a
const
object, in realityconst
objects in C (as opposed to C++) are not true constants and therefore are usually useless in most practical cases.So, in C the choice should be determined by how you plan to use your constant. For example, you can't use a
const int
object as acase
label (while a macro will work). You can't use aconst int
object as a bit-field width (while a macro will work). In C89/90 you can't use aconst
object to specify an array size (while a macro will work). Even in C99 you can't use aconst
object to specify an array size when you need a non-VLA array.If this is important for you then it will determine your choice. Most of the time, you'll have no choice but to use
#define
in C. And don't forget another alternative, that produces true constants in C -enum
.In C++
const
objects are true constants, so in C++ it is almost always better to prefer theconst
variant (no need for explicitstatic
in C++ though).static const
和#define
的区别在于前者使用内存,后者不使用内存进行存储。其次,您不能传递#define
的地址,而可以传递static const
的地址。其实这取决于我们在什么情况下,我们需要在这两者中选择其一。两人在不同的情况下都处于最佳状态。请不要假设一个比另一个更好... :-)如果情况确实如此,丹尼斯·里奇会保留最好的一个...哈哈哈...:-)
The difference between
static const
and#define
is that the former uses the memory and the later does not use the memory for storage. Secondly, you cannot pass the address of an#define
whereas you can pass the address of astatic const
. Actually it is depending on what circumstance we are under, we need to select one among these two. Both are at their best under different circumstances. Please don't assume that one is better than the other... :-)If that would have been the case, Dennis Ritchie would have kept the best one alone... hahaha... :-)
在 C 中,
#define
更为流行。您可以使用这些值来声明数组大小,例如:据我所知,ANSI C 不允许您在此上下文中使用
static const
。在 C++ 中,在这些情况下您应该避免使用宏。您可以编写甚至省略
static
,因为内部链接已由const
隐含[仅在 C++ 中]。In C
#define
is much more popular. You can use those values for declaring array sizes for example:ANSI C doesn't allow you to use
static const
s in this context as far as I know. In C++ you should avoid macros in these cases. You can writeand even leave out
static
because internal linkage is implied byconst
already [in C++ only].C 中
const
的另一个缺点是您无法在初始化另一个const
时使用该值。即使这也不适用于 const,因为编译器不会将其视为常量:
在这些情况下我很乐意使用类型化
const
,否则......Another drawback of
const
in C is that you can't use the value in initializing anotherconst
.Even this does not work with a const since the compiler does not see it as a constant:
I'd be happy to use typed
const
in these cases, otherwise...如果你能摆脱它,
static const
有很多优点。它遵循正常的作用域原则,在调试器中可见,并且通常遵循变量所遵循的规则。然而,至少在最初的 C 标准中,它实际上并不是一个常量。如果您使用#define var 5,则可以编写 int foo[var]; 作为声明,但您不能这样做(除非作为编译器扩展)
static const int var = 5;
在 C++ 中情况并非如此,其中static const
版本可以在#define
版本的任何地方使用。可以,而且我相信 C99 也是如此。但是,永远不要使用小写名称命名
#define
常量,它会覆盖该名称的任何可能使用,直到翻译单元结束。宏常量实际上应该位于它们自己的命名空间中,传统上全是大写字母,也许带有前缀。If you can get away with it,
static const
has a lot of advantages. It obeys the normal scope principles, is visible in a debugger, and generally obeys the rules that variables obey.However, at least in the original C standard, it isn't actually a constant. If you use
#define var 5
, you can writeint foo[var];
as a declaration, but you can't do that (except as a compiler extension" withstatic const int var = 5;
. This is not the case in C++, where thestatic const
version can be used anywhere the#define
version can, and I believe this is also the case with C99.However, never name a
#define
constant with a lowercase name. It will override any possible use of that name until the end of the translation unit. Macro constants should be in what is effectively their own namespace, which is traditionally all capital letters, perhaps with a prefix.最好使用 const,而不是 #define。这是因为 const 由编译器处理,#define 由预处理器处理。就像 #define 本身不是代码的一部分(粗略地说)。
示例:
符号名 PI 可能永远不会被编译器看到;在源代码到达编译器之前,它可能会被预处理器删除。因此,名称 PI 可能不会输入到符号表中。如果您在编译期间遇到涉及常量使用的错误,这可能会令人困惑,因为错误消息可能引用 3.1416,而不是 PI。如果 PI 是在您没有编写的头文件中定义的,那么您将不知道 3.1416 来自哪里。
这个问题也可能出现在符号调试器中,因为您正在编程的名称可能不在符号表中。
解决方案:
It is ALWAYS preferable to use const, instead of #define. That's because const is treated by the compiler and #define by the preprocessor. It is like #define itself is not part of the code (roughly speaking).
Example:
The symbolic name PI may never be seen by compilers; it may be removed by the preprocessor before the source code even gets to a compiler. As a result, the name PI may not get entered into the symbol table. This can be confusing if you get an error during compilation involving the use of the constant, because the error message may refer to 3.1416, not PI. If PI were defined in a header file you didn’t write, you’d have no idea where that 3.1416 came from.
This problem can also crop up in a symbolic debugger, because, again, the name you’re programming with may not be in the symbol table.
Solution:
如果你有像
mystruct.var
这样的东西,#define var 5
会给你带来麻烦。例如,
预处理器将替换它,并且代码将无法编译。因此,传统的编码风格建议所有常量
#define
都使用大写字母以避免冲突。#define var 5
will cause you trouble if you have things likemystruct.var
.For example,
The preprocessor will replace it and the code won't compile. For this reason, traditional coding style suggest all constant
#define
s uses capital letters to avoid conflict.我编写了快速测试程序来演示一个差异:
编译时会出现以下错误和警告:
请注意,当定义给出警告时,枚举会给出错误。
I wrote quick test program to demonstrate one difference:
This compiles with these errors and warnings:
Note that enum gives an error when define gives a warning.
尽管问题是关于整数,但值得注意的是,如果您需要常量结构或字符串,#define 和枚举是无用的。它们通常都作为指针传递给函数。 (对于字符串,这是必需的;对于结构,它的效率要高得多。)
至于整数,如果您处于内存非常有限的嵌入式环境中,您可能需要担心常量的存储位置以及如何编译对它的访问。编译器可能在运行时添加两个 const,但在编译时添加两个 #define。 #define 常量可以转换为一条或多条 MOV [立即] 指令,这意味着该常量有效地存储在程序存储器中。 const 常量通常存储在数据存储器中的单独部分中,例如 .const 或 .rodata。在具有哈佛架构的系统中,性能和内存使用可能存在差异,尽管差异可能很小。它们可能对于内部循环的核心优化很重要。
Although the question was about integers, it's worth noting that #define and enums are useless if you need a constant structure or string. These are both usually passed to functions as pointers. (With strings it's required; with structures it's much more efficient.)
As for integers, if you're in an embedded environment with very limited memory, you might need to worry about where the constant is stored and how accesses to it are compiled. The compiler might add two consts at run time, but add two #defines at compile time. A #define constant may be converted into one or more MOV [immediate] instructions, which means the constant is effectively stored in program memory. A const constant will usually be stored in a separate section in data memory such as .const or .rodata. In systems with a Harvard architecture, there could be differences in performance and memory usage, although they'd likely be small. They might matter for hard-core optimization of inner loops.
该定义
并不总是定义一个常量值。某些编译器(例如 tcc 0.9.26)仅分配名称为“const_value”的内存。使用标识符“const_value”您不能修改该内存。但是您仍然可以使用另一个标识符修改内存:
这意味着定义是定义
不能以任何方式修改的常量值的唯一方法。
The definition
does not always define a constant value. Some compilers (for example tcc 0.9.26) just allocate memory identified with the name "const_value". Using the identifier "const_value" you can not modify this memory. But you still could modify the memory using another identifier:
This means the definition
is the only way to define a constant value which can not be modified by any means.
不要认为“哪个总是最好的”有答案,但是,正如 Matthieu 所说,
static const
是类型安全的。不过,我对
#define
最大的不满是在 Visual Studio< 中进行调试时/a> 您无法观察该变量。它给出了找不到符号的错误。Don't think there's an answer for "which is always best" but, as Matthieu said
static const
is type safe. My biggest pet peeve with
#define
, though, is when debugging in Visual Studio you cannot watch the variable. It gives an error that the symbol cannot be found.顺便说一句,
#define
的替代方案是“enum”,它提供了适当的范围,但表现得像“真正的”常量。例如:在许多情况下,定义枚举类型并创建这些类型的变量很有用;如果这样做了,调试器也许能够根据变量的枚举名称来显示变量。
然而,这样做的一个重要警告是:在 C++ 中,枚举类型与整数的兼容性有限。例如,默认情况下,无法对它们执行算术运算。我发现这是枚举的一个奇怪的默认行为;虽然拥有“严格枚举”类型会很好,但考虑到 C++ 与 C 普遍兼容的愿望,我认为“枚举”类型的默认行为应该与整数互换。
Incidentally, an alternative to
#define
, which provides proper scoping but behaves like a "real" constant, is "enum". For example:In many cases, it's useful to define enumerated types and create variables of those types; if that is done, debuggers may be able to display variables according to their enumeration name.
One important caveat with doing that, however: in C++, enumerated types have limited compatibility with integers. For example, by default, one cannot perform arithmetic upon them. I find that to be a curious default behavior for enums; while it would have been nice to have a "strict enum" type, given the desire to have C++ generally compatible with C, I would think the default behavior of an "enum" type should be interchangeable with integers.
一个简单的区别:
在预处理时,常量被替换为它的值。
因此,您无法将取消引用运算符应用于定义,但可以将取消引用运算符应用于变量。
正如您所想,define 比 static const 更快。
例如,
您不能执行
printf("address ofconstant is %p",&mymax);
。但是
你可以这样做
printf("address ofconstant is %p",&mymax_var);
。更清楚地说,定义在预处理阶段被它的值替换,因此我们没有在程序中存储任何变量。我们只有使用定义的程序文本段中的代码。
然而,对于 static const,我们有一个分配在某处的变量。对于gcc来说,static const分配在程序的文本段中。
上面,我想讲述引用运算符,因此将取消引用替换为引用。
A simple difference:
At pre-processing time, the constant is replaced with its value.
So you could not apply the dereference operator to a define, but you can apply the dereference operator to a variable.
As you would suppose, define is faster that static const.
For example, having:
you can not do
printf("address of constant is %p",&mymax);
.But having
you can do
printf("address of constant is %p",&mymax_var);
.To be more clear, the define is replaced by its value at the pre-processing stage, so we do not have any variable stored in the program. We have just the code from the text segment of the program where the define was used.
However, for static const we have a variable that is allocated somewhere. For gcc, static const are allocated in the text segment of the program.
Above, I wanted to tell about the reference operator so replace dereference with reference.
我们查看了 MBF16X 上生成的汇编代码...两种变体都会产生相同的算术运算代码(例如 ADD Immediate)。
因此,
const int
是类型检查的首选,而#define
是旧式。也许它是特定于编译器的。因此,请检查您生成的汇编代码。We looked at the produced assembler code on the MBF16X... Both variants result in the same code for arithmetic operations (ADD Immediate, for example).
So
const int
is preferred for the type check while#define
is old style. Maybe it is compiler-specific. So check your produced assembler code.我不确定我是否正确,但在我看来,调用
#define
d value 比调用任何其他正常声明的变量(或 const 值)要快得多。这是因为当程序运行时,它需要使用一些正常声明的变量,它需要跳转到内存中的确切位置来获取该变量。
相反,当使用
#define
d值时,程序不需要跳转到任何分配的内存;它只需要值。如果#define myValue 7
且程序调用myValue
,则其行为与仅调用7
时的行为完全相同。I am not sure if I am right, but in my opinion calling
#define
d value is much faster than calling any other normally declared variable (or const value).It's because when program is running and it needs to use some normally declared variable, it needs to jump to exact place in memory to get that variable.
In opposite, when it uses
#define
d value, the program doesn't need to jump to any allocated memory; it just takes the value. If#define myValue 7
and the program callingmyValue
, it behaves exactly the same as when it just calls7
.