“静态常量”与“#define”相比与“枚举”

发布于 2024-08-09 18:30:34 字数 182 浏览 6 评论 0 原文

下面的 C 语言语句中,哪一个更好用?

static const int var = 5;

#define var 5

enum { var = 5 };

Which one is better to use among the below statements in C?

static const int var = 5;

or

#define var 5

or

enum { var = 5 };

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(17

琉璃梦幻 2024-08-16 18:30:34

这取决于您需要什么价值。您(以及到目前为止的其他人)省略了第三种选择:

  1. static const int var = 5;
  2. #define var 5
  3. enum { var = 5 }; code>

忽略有关名称选择的问题,那么:

  • 如果需要传递指针,则必须使用 (1)。
  • 由于 (2) 显然是一个选项,因此您不需要传递指针。
  • (1) 和 (3) 在调试器的符号表中都有一个符号 - 这使得调试更容易。 (2) 更有可能没有符号,让您想知道它是什么。
  • (1) 不能用作全局范围内数组的维度; (2)和(3)都可以。
  • (1) 不能在函数作用域内用作静态数组的维度; (2)和(3)都可以。
  • 在C99下,所有这些都可以用于本地数组。从技术上讲,使用 (1) 意味着使用 VLA(可变长度数组),尽管“var”引用的维度当然会固定为 5。
  • (1) 不能用在 switch 语句等地方; (2)和(3)都可以。
  • (1)不能用来初始化静态变量; (2)和(3)都可以。
  • (2) 可以更改您不想更改的代码,因为它由预处理器使用; (1)和(3)都不会产生这样意想不到的副作用。
  • 可以检测预处理器中是否设置了(2); (1) 和 (3) 都不允许这样做。

因此,在大多数情况下,更喜欢“枚举”而不是其他选择。否则,第一个和最后一个要点很可能是控制因素——如果你需要同时满足这两个要点,你就必须更加努力地思考。

如果您询问有关 C++ 的问题,那么您每次都会使用选项 (1) - static const。

It depends on what you need the value for. You (and everyone else so far) omitted the third alternative:

  1. static const int var = 5;
  2. #define var 5
  3. enum { var = 5 };

Ignoring issues about the choice of name, then:

  • If you need to pass a pointer around, you must use (1).
  • Since (2) is apparently an option, you don't need to pass pointers around.
  • Both (1) and (3) have a symbol in the debugger's symbol table - that makes debugging easier. It is more likely that (2) will not have a symbol, leaving you wondering what it is.
  • (1) cannot be used as a dimension for arrays at global scope; both (2) and (3) can.
  • (1) cannot be used as a dimension for static arrays at function scope; both (2) and (3) can.
  • Under C99, all of these can be used for local arrays. Technically, using (1) would imply the use of a VLA (variable-length array), though the dimension referenced by 'var' would of course be fixed at size 5.
  • (1) cannot be used in places like switch statements; both (2) and (3) can.
  • (1) cannot be used to initialize static variables; both (2) and (3) can.
  • (2) can change code that you didn't want changed because it is used by the preprocessor; both (1) and (3) will not have unexpected side-effects like that.
  • You can detect whether (2) has been set in the preprocessor; neither (1) nor (3) allows that.

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.

饮惑 2024-08-16 18:30:34

一般来说:

static const

因为它尊重范围并且是类型安全的。

我能看到的唯一警告:如果您希望变量可能在命令行上定义。还有一个替代方案:

#ifdef VAR // Very bad name, not long enough, too general, etc..
  static int const var = VAR;
#else
  static int const var = 5; // default value
#endif

只要有可能,就使用类型安全的替代方案来代替宏/省略号。

如果您确实需要使用宏(例如,您想要 __FILE____LINE__),那么您最好非常仔细地命名您的宏:在其 命名约定 Boost 建议全部大写,以项目名称开头(此处为 BOOST_),在仔细阅读库时,您会注意到(通常)后面跟着特定的名称区域(图书馆),然后用一个有意义的名称。

它通常会导致名字很长:)

Generally speaking:

static const

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:

#ifdef VAR // Very bad name, not long enough, too general, etc..
  static int const var = VAR;
#else
  static int const var = 5; // default value
#endif

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 :)

一指流沙 2024-08-16 18:30:34

具体来说,在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 reality const 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 a case label (while a macro will work). You can't use a const int object as a bit-field width (while a macro will work). In C89/90 you can't use a const object to specify an array size (while a macro will work). Even in C99 you can't use a const 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 the const variant (no need for explicit static in C++ though).

故人爱我别走 2024-08-16 18:30:34

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 a static 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... :-)

朦胧时间 2024-08-16 18:30:34

在 C 中,#define 更为流行。您可以使用这些值来声明数组大小,例如:

#define MAXLEN 5

void foo(void) {
   int bar[MAXLEN];
}

据我所知,ANSI C 不允许您在此上下文中使用static const。在 C++ 中,在这些情况下您应该避免使用宏。您可以编写

const int maxlen = 5;

void foo() {
   int bar[maxlen];
}

甚至省略 static,因为内部链接已由 const 隐含[仅在 C++ 中]。

In C #define is much more popular. You can use those values for declaring array sizes for example:

#define MAXLEN 5

void foo(void) {
   int bar[MAXLEN];
}

ANSI C doesn't allow you to use static consts in this context as far as I know. In C++ you should avoid macros in these cases. You can write

const int maxlen = 5;

void foo() {
   int bar[maxlen];
}

and even leave out static because internal linkage is implied by const already [in C++ only].

∝单色的世界 2024-08-16 18:30:34

C 中 const 的另一个缺点是您无法在初始化另一个 const 时使用该值。

static int const NUMBER_OF_FINGERS_PER_HAND = 5;
static int const NUMBER_OF_HANDS = 2;

// initializer element is not constant, this does not work.
static int const NUMBER_OF_FINGERS = NUMBER_OF_FINGERS_PER_HAND 
                                     * NUMBER_OF_HANDS;

即使这也不适用于 const,因为编译器不会将其视为常量:

static uint8_t const ARRAY_SIZE = 16;
static int8_t const lookup_table[ARRAY_SIZE] = {
    1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}; // ARRAY_SIZE not a constant!

在这些情况下我很乐意使用类型化 const,否则......

Another drawback of const in C is that you can't use the value in initializing another const.

static int const NUMBER_OF_FINGERS_PER_HAND = 5;
static int const NUMBER_OF_HANDS = 2;

// initializer element is not constant, this does not work.
static int const NUMBER_OF_FINGERS = NUMBER_OF_FINGERS_PER_HAND 
                                     * NUMBER_OF_HANDS;

Even this does not work with a const since the compiler does not see it as a constant:

static uint8_t const ARRAY_SIZE = 16;
static int8_t const lookup_table[ARRAY_SIZE] = {
    1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}; // ARRAY_SIZE not a constant!

I'd be happy to use typed const in these cases, otherwise...

动听の歌 2024-08-16 18:30:34

如果你能摆脱它,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 write int foo[var]; as a declaration, but you can't do that (except as a compiler extension" with static const int var = 5;. This is not the case in C++, where the static 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.

初与友歌 2024-08-16 18:30:34

最好使用 const,而不是 #define。这是因为 const 由编译器处理,#define 由预处理器处理。就像 #define 本身不是代码的一部分(粗略地说)。

示例:

#define PI 3.1416

符号名 PI 可能永远不会被编译器看到;在源代码到达编译器之前,它可能会被预处理器删除。因此,名称 PI 可能不会输入到符号表中。如果您在编译期间遇到涉及常量使用的错误,这可能会令人困惑,因为错误消息可能引用 3.1416,而不是 PI。如果 PI 是在您没有编写的头文件中定义的,那么您将不知道 3.1416 来自哪里。

这个问题也可能出现在符号调试器中,因为您正在编程的名称可能不在符号表中。

解决方案:

const double PI = 3.1416; //or static const...

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:

#define PI 3.1416

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:

const double PI = 3.1416; //or static const...
追星践月 2024-08-16 18:30:34

如果你有像 mystruct.var 这样的东西,#define var 5 会给你带来麻烦。

例如,

struct mystruct {
    int var;
};

#define var 5

int main() {
    struct mystruct foo;
    foo.var = 1;
    return 0;
}

预处理器将替换它,并且代码将无法编译。因此,传统的编码风格建议所有常量#define都使用大写字母以避免冲突。

#define var 5 will cause you trouble if you have things like mystruct.var.

For example,

struct mystruct {
    int var;
};

#define var 5

int main() {
    struct mystruct foo;
    foo.var = 1;
    return 0;
}

The preprocessor will replace it and the code won't compile. For this reason, traditional coding style suggest all constant #defines uses capital letters to avoid conflict.

冧九 2024-08-16 18:30:34

我编写了快速测试程序来演示一个差异:

#include <stdio.h>

enum {ENUM_DEFINED=16};
enum {ENUM_DEFINED=32};

#define DEFINED_DEFINED 16
#define DEFINED_DEFINED 32

int main(int argc, char *argv[]) {

   printf("%d, %d\n", DEFINED_DEFINED, ENUM_DEFINED);

   return(0);
}

编译时会出现以下错误和警告:

main.c:6:7: error: redefinition of enumerator 'ENUM_DEFINED'
enum {ENUM_DEFINED=32};
      ^
main.c:5:7: note: previous definition is here
enum {ENUM_DEFINED=16};
      ^
main.c:9:9: warning: 'DEFINED_DEFINED' macro redefined [-Wmacro-redefined]
#define DEFINED_DEFINED 32
        ^
main.c:8:9: note: previous definition is here
#define DEFINED_DEFINED 16
        ^

请注意,当定义给出警告时,枚举会给出错误。

I wrote quick test program to demonstrate one difference:

#include <stdio.h>

enum {ENUM_DEFINED=16};
enum {ENUM_DEFINED=32};

#define DEFINED_DEFINED 16
#define DEFINED_DEFINED 32

int main(int argc, char *argv[]) {

   printf("%d, %d\n", DEFINED_DEFINED, ENUM_DEFINED);

   return(0);
}

This compiles with these errors and warnings:

main.c:6:7: error: redefinition of enumerator 'ENUM_DEFINED'
enum {ENUM_DEFINED=32};
      ^
main.c:5:7: note: previous definition is here
enum {ENUM_DEFINED=16};
      ^
main.c:9:9: warning: 'DEFINED_DEFINED' macro redefined [-Wmacro-redefined]
#define DEFINED_DEFINED 32
        ^
main.c:8:9: note: previous definition is here
#define DEFINED_DEFINED 16
        ^

Note that enum gives an error when define gives a warning.

长安忆 2024-08-16 18:30:34

尽管问题是关于整数,但值得注意的是,如果您需要常量结构或字符串,#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.

橙味迷妹 2024-08-16 18:30:34

该定义

const int const_value = 5;

并不总是定义一个常量值。某些编译器(例如 tcc 0.9.26)仅分配名称为“const_value”的内存。使用标识符“const_value”您不能修改该内存。但是您仍然可以使用另一个标识符修改内存:

const int const_value = 5;
int *mutable_value = (int*) &const_value;
*mutable_value = 3;
printf("%i", const_value); // The output may be 5 or 3, depending on the compiler.

这意味着定义是定义

#define CONST_VALUE 5

不能以任何方式修改的常量值的唯一方法。

The definition

const int const_value = 5;

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:

const int const_value = 5;
int *mutable_value = (int*) &const_value;
*mutable_value = 3;
printf("%i", const_value); // The output may be 5 or 3, depending on the compiler.

This means the definition

#define CONST_VALUE 5

is the only way to define a constant value which can not be modified by any means.

长发绾君心 2024-08-16 18:30:34

不要认为“哪个总是最好的”有答案,但是,正如 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.

空宴 2024-08-16 18:30:34

顺便说一句,#define 的替代方案是“enum”,它提供了适当的范围,但表现得像“真正的”常量。例如:

enum {number_ten = 10};

在许多情况下,定义枚举类型并创建这些类型的变量很有用;如果这样做了,调试器也许能够根据变量的枚举名称来显示变量。

然而,这样做的一个重要警告是:在 C++ 中,枚举类型与整数的兼容性有限。例如,默认情况下,无法对它们执行算术运算。我发现这是枚举的一个奇怪的默认行为;虽然拥有“严格枚举”类型会很好,但考虑到 C++ 与 C 普遍兼容的愿望,我认为“枚举”类型的默认行为应该与整数互换。

Incidentally, an alternative to #define, which provides proper scoping but behaves like a "real" constant, is "enum". For example:

enum {number_ten = 10};

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.

日暮斜阳 2024-08-16 18:30:34

一个简单的区别:

在预处理时,常量被替换为它的值。
因此,您无法将取消引用运算符应用于定义,但可以将取消引用运算符应用于变量。

正如您所想,define 比 static const 更快。

例如,

#define mymax 100

您不能执行 printf("address ofconstant is %p",&mymax);

但是

const int mymax_var=100

你可以这样做 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:

#define mymax 100

you can not do printf("address of constant is %p",&mymax);.

But having

const int mymax_var=100

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.

帅冕 2024-08-16 18:30:34

我们查看了 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.

ζ澈沫 2024-08-16 18:30:34

我不确定我是否正确,但在我看来,调用 #defined value 比调用任何其他正常声明的变量(或 const 值)要快得多。

这是因为当程序运行时,它需要使用一些正常声明的变量,它需要跳转到内存中的确切位置来获取该变量。

相反,当使用#defined值时,程序不需要跳转到任何分配的内存;它只需要值。如果#define myValue 7 且程序调用myValue,则其行为与仅调用7 时的行为完全相同。

I am not sure if I am right, but in my opinion calling #defined 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 #defined value, the program doesn't need to jump to any allocated memory; it just takes the value. If #define myValue 7 and the program calling myValue, it behaves exactly the same as when it just calls 7.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文