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

static const int var = 5;

要么

#define var 5

要么

enum { var = 5 };

#1楼

如果您具有诸如mystruct.var类的内容, mystruct.var #define var 5将会给您带来麻烦。

例如,

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

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


#2楼

一般来说:

static const

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

我唯一看到的警告是:是否希望在命令行上定义变量。 还有一种选择:

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

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

如果确实需要使用宏(例如,您想要__FILE____LINE__ ),则最好非常小心地命名宏:在其命名约定中, Boost建议所有大写字母,以项目名称开头(此处是BOOST_),在细读库时,您会注意到(通常)后跟特定区域(库)的名称,然后加上有意义的名称。

通常,它使用冗长的名称:)


#3楼

不要以为“永远是最好的”是有答案的,但是正如Matthieu所说

static const

是类型安全的。 但是,我最大的#define烦恼是,在Visual Studio中进行调试时,您无法监视该变量。 出现错误,找不到该符号。


#4楼

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

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

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

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

甚至不包含static因为const已经隐含了内部链接[仅在C ++中]。


#5楼

特别是在C中? 在C语言中,正确的答案是:使用#define (或者,如果合适,使用enum

虽然具有const对象的作用域和类型属性是有益的,但实际上C中的const对象(与C ++相反)不是真正的常数,因此在大多数实际情况下通常是无用的。

因此,在C语言中,选择应取决于计划使用常量的方式。 例如,您不能将const int对象用作case标签(而宏将起作用)。 您不能将const int对象用作位域宽度(而宏将起作用)。 在C89 / 90中,您不能使用const对象指定数组大小(而宏将起作用)。 即使在C99中,当您需要非VLA数组时,也无法使用const对象指定数组大小。

如果这对您很重要,那么它将决定您的选择。 在大多数情况下,您别无选择,只能在C中使用#define 。并且不要忘了另一种选择,它会在C- enum中产生真正的常量。

在C ++中, const对象是真正的常量,因此在C ++中,最好总是首选const变体(尽管C ++中不需要显式static )。


#6楼

如果可以摆脱它, static const具有很多优点。 它遵循正常的作用域原则,在调试器中可见,并且通常遵循变量遵循的规则。

但是,至少在最初的C标准中,它实际上不是常数。 如果使用#define var 5 ,则可以编写int foo[var]; 作为声明,但您不能这样做(除了作为编译器扩展之外, static const int var = 5;在C ++中不是这种情况,因为static const版本可以在#define版本可以使用的任何地方使用,我相信C99也是如此。

但是,切勿使用小写字母命名#define常数。 在翻译单元末尾之前,它将覆盖该名称的所有可能用法。 宏常量应该有效地位于它们自己的名称空间中,该名称空间传统上是所有大写字母,可能带有前缀。


#7楼

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

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

忽略有关名称选择的问题,然后:

  • 如果需要传递指针,则必须使用(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)-静态const。


#8楼

static const#define之间的区别在于,前者使用内存,而后者不使用内存进行存储。 其次,您不能传递#define的地址,而可以传递static const的地址。 实际上,这取决于我们所处的环境,我们需要在这两种情况中选择一种。 两者在不同情况下都处于最佳状态。 请不要以为一个优于另一个... :-)

如果真是那样的话, 丹尼斯·里奇本该保持最好的一个……哈哈哈……:-)


#9楼

定义

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

是定义不能以任何方式修改的常数值的唯一方法。


#10楼

一个简单的区别:

在预处理时,常数将替换为其值。 因此,您不能将取消引用运算符应用于定义,但是可以将取消引用运算符应用于变量。

如您所愿,define比静态const更快。

例如,具有:

#define mymax 100

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

但是有

const int mymax_var=100

您可以执行printf("address of constant is %p",&mymax_var);

更清楚地说,在预处理阶段,定义将被其值替换,因此程序中没有存储任何变量。 我们只有使用定义的程序文本段中的代码。

但是,对于静态const,我们有一个分配在某处的变量。 对于gcc,静态const分配在程序的文本段中。

上面,我想介绍一下引用运算符,所以用引用替换取消引用。


#11楼

始终最好使用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...

#12楼

我们在MBF16X上查看了产生的汇编代码。这两种变体在算术运算中都产生相同的代码(例如,ADD Instant)。

因此,在#define为旧样式时,最好使用const int作为类型检查。 也许是特定于编译器的。 因此,请检查您生成的汇编代码。


#13楼

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

#include <stdio.h>enum {ENUM_DEFINED=16};
enum {ENUM_DEFINED=32};#define DEFINED_DEFINED 16
#define DEFINED_DEFINED 32int 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^

请注意,当define给出警告时,enum给出错误。


#14楼

顺便提一下,# #define的替代方法是“枚举”,该替代方法提供适当的作用域,但其行为类似于“真实”常量。 例如:

enum {number_ten = 10;}

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

但是,这样做的一个重要警告是:在C ++中,枚举类型与整数的兼容性有限。 例如,默认情况下,不能对它们执行算术运算。 我发现这对于枚举是一种奇怪的默认行为。 尽管有一个“严格的枚举”类型会很好,但考虑到C ++通常与C兼容的愿望,我认为“枚举”类型的默认行为应该可以与整数互换。


#15楼

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 ,否则...


#16楼

尽管问题是关于整数的,但值得注意的是,如果需要恒定的结构或字符串,则#define和enum是无用的。 这些通常都作为指针传递给函数。 (使用字符串是必需的;使用结构则效率更高。)

至于整数,如果您处于内存非常有限的嵌入式环境中,则可能需要担心常量存储在何处以及如何编译对其的访问。 编译器可能会在运行时添加两个const,但在编译时添加两个#define。 可以将#define常数转换为一个或多个MOV [立即]指令,这意味着该常数有效地存储在程序存储器中。 常量将存储在数据存储器的.const节中。 在具有哈佛体系结构的系统中,性能和内存使用量可能会有所不同,尽管它们可能很小。 它们对于内部循环的硬核优化可能很重要。


#17楼

我不确定我是否正确,但是我认为调用#define d值比调用任何其他通常声明的变量(或const值)要快得多。 这是因为在程序运行时,它需要使用一些通常声明的变量,因此需要跳转到内存中的确切位置以获取该变量。

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

“静态常量”与“ #define”与“枚举”相关推荐

  1. C ++基础 | sizeof函数(endl 和 \ n),定义常量(Define Constants),枚举常量(Enumerated Constants)_2

    目录 sizeof函数(endl 和 "\ n") 定义常量 枚举常量 sizeof函数(endl 和 "\ n") 与其他编程语言一样,在内存中分配变量的大小 ...

  2. Mybatis引用静态常量或者枚举类型

    语法规则: ${@path$subClass@Attr.getValueMethod} 例子: <select id="listModelsToProTps" resultT ...

  3. C++ 笔记(07)— 常量(字面常量、const定义常量、constexpr 定义常量、enum 定义常量、define 定义常量)

    在 C++ 中,常量类似于变量,只是不能修改.与变量一样,常量也占用内存空间,并使用名称标识为其预留的空间的地址,但不能覆盖该空间的内容. 常量可以是任何的基本数据类型,可分为整型数字.浮点数字.字符 ...

  4. 单例设计模式介绍||单例设计模式八种方式——1) 饿汉式(静态常量) 2) 饿汉式(静态代码块) 3) 懒汉式(线程不安全) 4) 懒汉式(线程安全,同步方法)

    单例模式 单例设计模式介绍 所谓类的单例设计模式,就是采取一定的方法保证在整个的软件系统中,对某个类只能存在一个对象实例,并且该类只提供一个取得其对象实例的方法(静态方法). 比如Hibernate的 ...

  5. Java 静态变量,静态方法,静态常量(java static 关键字)

    Java 静态变量,静态方法,静态常量  就是变量 ,方法,常量前面添加了static 关键字 为什么要使用静态的呢 有时候在处理问题时会需要两个类在同一个内存区域共享一个数据, 不如现在 Main ...

  6. php----------const 定义的常量和define()定义的常量的区别?

    用法一:const用于类成员变量,一经定义不可修改,define用于全局常量,不可用于类成员变量的定义,const可在类中使用也可以在类外面使用,define不能. 定义:const 常量名=值; 没 ...

  7. Java虚拟机的静态常量池和运行时常量池

    (静态)常量池:用于存放编译器生成的各种字面量和符号引用(符号引用区别于直接引用,后者在class字节码文件被虚拟机解析之后,符号引用将被替换为直接引用). 运行时常量池:(静态)常量池中的内容在类加 ...

  8. iOS定义静态变量、静态常量、全局变量

    原文链接: iOS定义静态变量.静态常量.全局变量 简书主页:http://www.jianshu.com/users/37f2920f6848 Github主页:https://github.com ...

  9. 关于类中的引用、常量、静态常量的初始化

    不过 下面所说的在新的 c++11中,已经有所改变. 比如程序中: static const double csd2 = 99.8; // error: 只有静态常量整型数据成员才可以在类中初始化 已 ...

最新文章

  1. 基于TensorRT优化的Machine Translation
  2. 谈谈职业规划——CSDN对我的采访
  3. DCMTK:创建,写入和读取二进制细分对象
  4. mui 组件:“div下拉导航”【scroll固定位置】- 案例篇
  5. C# 获取枚举的DescriptionAttribute内的字符串
  6. 实地踩坑,新鲜出炉,阿里云GPU服务器Centos7.7深度学习环境搭建实战
  7. 解决SecoClient接收返回码超时
  8. 浪潮服务器系统驱动,浪潮英信服务器驱动(最新更新)浪潮网卡驱动
  9. NUCLEO开发板:STM32 st-link驱动程序错误
  10. 计算机打印错误,打印机错误正在打印处理方法,教您电脑打印机错误正在打印处理方法...
  11. CentOs解压缩命令
  12. 玩转prometheus告警 alertmanger(二)之alertmanger 邮件 钉钉告警
  13. 如何指定火狐浏览器打开网页
  14. 华为手机便签有扫描的功能么
  15. Mina2框架--服务端与客户端通信
  16. aps自动排程助企业缩短制造周期
  17. 迄今为止最全的技术文档汇总,编程语言,操作系统,数据结构,设计模式等赶紧收藏起来。
  18. StarGAN v2 : Diverse Image Synthesis for Multiple Domains 不同图像多领域合成阅读理解
  19. 局域网共享技术及网络故障检测排除
  20. 微信小程序学习笔记(七)----简单文章推荐列表和分类图标的实现

热门文章

  1. adb shell am 命令启动activity、Service、Borascast
  2. Android 微信支付步骤
  3. todomvp 谷歌的MVP实例
  4. Android左边有固定文字的EditText
  5. 源码分析Handler机制
  6. SQLite-Java-Hibernate类似hibernate的数据库辅助工具
  7. 【UIKit】UIAlertController使用
  8. java 包含汉字,【转载】Java判断字符串中是不是包含汉字
  9. django中判断当前user具有是否有对模块的增删改查权限
  10. 根据痛点分析制作软件