C++-C++ 各种全局常量的声明方式的优缺点?

C++-C++ 各种全局常量的声明方式的优缺点?

想挽留 发布于 2017-03-05 字数 280 浏览 1240 回复 9

在一些比较大的工程中,经常会用到很多全局常量,这些常量的声明方式有很多种。
比如:宏常量 #define XXXXX = 0x00
枚举常量 enum{ YYYYY = 0, ZZZZZ = 1 };
……
除此之外还有什么常量声明方式?
这些常量声明方式有什么优缺点?
在什么情况下该用哪种常量?

如果你对这篇文章有疑问,欢迎到本站 社区 发帖提问或使用手Q扫描下方二维码加群参与讨论,获取更多帮助。

扫码加入群聊

发布评论

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

评论(9

偏爱自由 2017-10-21 9 楼

《Effecitve C++》里建议用const

夜无邪 2017-10-13 8 楼

宏定义可以叫做全局常量吗?这我倒不清楚了。它就是一个常量而已,而且理论上是没什么不好的,宏定义只是文本复制。
如果你说的是希望整个工程项目都能用到的常量,的确大部分都会用宏定义的方式定义出来。
而枚举常量在Linux的内核代码中也很常见,不过更多是出现于定义一个错误代码,即希望1是代码错误a,2是代表错误b,但是很少作为全局的常量来声明。
我看来实际上代码中会出现全局的常量的情况很少,(我指的是占内存空间的,不是说像宏定义那样的。)因为非得要定义一个全局的常量的话,将它用宏定义声明会好很多。印象中只见过没办法只能定义全局变量的,可能我读的代码量不多。

参考后面几位的答案,再确认了一番。
在C++里头确实不提倡用#define,然后对Effective C++说的,也小怀疑了一下,我觉得是这样的,对于一个可以成为立即数的常量来说(即大小小于寄存器可以存的数的大小),define还是有优势的,翻译成汇编就知道了,立即数不用另外开辟空间来存储,我觉得编译器会做好这个优化(Effective C++说的也不完全对啊!)。但是对于一个不能作为立即数的常量来说,编译器编译代码的时候,一定会在data段再开辟一段空间专门放这个常量,然后用到的时候就会寻址找到这个常量来使用,用define的时候,用多少次,data段内就会出现多少次,而用const来定义的时候,无论用多少次,data段内也只会有一次,所以节省了代码空间。

瑾兮 2017-10-07 7 楼

1)宏不是全局常量,只是预编译,编译器在编译前做字符串替换。

2)C++中用const声明常量 const type name = value; 这个比宏好的是:其有类型检查。

3)enum 不是定义常量语义,是一种定义只能有某种取值类型语义。

4)全局变/常量千万不要定义在头文件中,而是declare在h文件,define在c/cpp文件中,如:

 //t.c
const int g_int =10;

//t.h
extern const int g_int;

5)全局变量/常量应该全部定义在一个文件中,如果定义在不同的文件中,那么编译器将无法保证初始化顺序。

下面的这种情况可能会让a初始异常。

 //a.c
int a = b*2;

//b.c
int b=10;

6)全局的变量/常量最好放在namespace中,以防避免变量冲突。尤其是和local variable的冲突,编译器和运行都是不会出错的。

夜无邪 2017-10-03 6 楼

这是宏定义,不是常量,常量是const,防止被修改,宏变量方便统一,维护

甜柠檬 2017-09-25 5 楼

我个人观点是尽量少用,全局常量太多会污染命名空间的。

归属感 2017-09-15 4 楼

宏常量只是编译前的文本替换而已,没有类型检查,宏常量也不能调试。所以宏很容易引入错误。
#define PI 3.14159
如果改为 #define PI asdf //没有类型检查的 也不会报错。
const double PI = 3.14159;
使用 double area = PIrr; //类型安全
在C++ 中常量不要使用宏去定义,如果是常量 在c++可以使用const 常量 去代替C语言中的宏。

使用枚举常量的优点是有清晰的语意,并且同个枚举类型中的各个常量必须是有关联的。例如
enum Color {RED,GREEN}; 这样你就知道这些是代表颜色的值。不要定义不论不类的枚举类型例如:enum Color {LENGTH,RED}。枚举类型定义常量可以提高代码的可读性。

清晨说ぺ晚安 2017-07-25 3 楼

(1)#define pi 3.14 就是在编译的时候简单的替换,我觉得叫常数。
(2)常量和变量相对。变量可变,常量不可变。
(3)全局常量一般使用就是头文件声明,c/cpp定义。
(4)枚举变量主要就是给多个相似的名字编了几个号。只能是整形。

夜无邪 2017-07-09 2 楼

尽量少用宏,具体可参考《Effecitve C++》条款2:
最好以const对象或enums替换#defines

虐人心 2017-05-08 1 楼

我说几点不同意见:
(1) 一般用途的const变量,绝对不应该声明在头文件,定义在cpp里,尤其是基础类型(int之类)这个和inline函数是类似的,编译器能自动处理不同cpp中有同样const的问题;如果不使用const变量的地址,这个const变量最终会被完全优化掉,不占静态存储空间。而如果定义成extern,会导致编译器不得不为这个变量分配一个地址,并且在使用的时候强制地去从地址取得值,这会导致极大的性能下降。比如:

const int a = 16;

inline int sqr(x)
{
return a * a;
}

myFunc(sqr(a));

在这里,编译器可以把整个sqr(a)都优化掉,替换成一个立即数256。而如果a定义成了extern,这里就必须是读数值、乘法、传参数的过程了。
C++中编译器对于const变量做了充分的优化,它完全可以取代#define常量的一切功能。
比如:

const int MAX_N = 100;

int myArray[MAX_N];

在遇到使用const变量的时候,编译器如果已知const变量的值,就会直接把值代入进行优化,和#define是完全一样的。如果最后const变量没有取地址之类的操作,编译器就会认为这个变量没有被实际引用,于是在生成代码的最后把整个const变量去掉。
const变量如果不另加定义,默认就是static的。特意去定义成extern只会破坏编译器效率。这个和C是完全不同的,所以不要把C的法则想当然地用进来。
不过对于const变量类型是复杂类型(类)的时候,static的类型可能会导致每个cpp里面都生成一个对象,这时候应该考虑extern。

(2) const变量和#define宏相比最大的好处其实不在于类型检查,而在于可以有命名空间

 namespace MyNameSpace
{
#define myMacro 15
class MyClass
{
public:
const static int myConst = 15;
#define myMacro2 16
}
const int myConst2 = 16;
}

myConst必须用MyNameSpace::MyClass::myConst来引用,myConst2对应MyNameSpace::myConst2,而#define的两个常量永远都是myMacro和myMacro2,这意味着#define的常量重名的可能性要大得多,而且很容易破坏OOP结构。

(3) 特殊情况下#define和const比可能会引起问题。比如函数重载:

 void myFunc(int x)
{
...
}

void myFunc(short x)
{
...
}

const short myConst = 128;
#define myMacro 128

myFunc(myConst);
myFunc(myMacro);

#define由于没有类型,会去调用int版本的函数。这是const强制类型检查的好处

(4) const类型的编译效率比较好
因为编译器在编译的时候已经知道这个符号对应的是某类型的数了,编译会快一些。对运行影响不大。还有:

 #define MAXN (12*14)
const int MAX_N = 12 * 14;

使用MAXN的时候,编译器每次都得对表达式求值;MAX_N的话,只求了一次。

(5) const类型不容易出错
这个问题是老生常谈了,#define MACRO 12+13这种写法会出问题,必须加括号。const就没这个问题。

(6) enum
enum其实可以看做是定义了一族const变量。它们同样也有命名空间,同样也有变量类型(不过变量类型是enum XXX),额外的,enum定义的常量不会使用额外的内存空间。缺点在于:enum定义的常量,类型是enum XXX,不是int。虽然可以和int型数值无限制地转换,但毕竟不是int,使用上不是那么方便,比如不能直接做加减乘除之类。

(7) #define的优势
#define在C++中的作用一般已经不是定义常量或者宏了,如前文所说这些功能应该由const和inline函数来代替。#define在C++中可以用来定义一些快捷语法,或者是根据编译选项不同生成不同内容:
#define L(x) L##x
L("abcde") // L"abcde"

#ifdef _UNICODE
#define MyFunc MyFuncW
#else
#define MyFunc MyFuncA
#endif

这些功能目前还没有其他语法可以替代。