我正在阅读《C++ 编码标准:101 条规则、指南和最佳实践》一书,它说使用#define
不好。当我查看一些头文件时,它们有很多#define
s. 如果用#define
s不好,为什么会有这么多?谢谢你。
3 回答
#define
是一种不好的做法,因为:
他们没有任何范围:
#define
s 不尊重范围,因此无法创建类范围命名空间。虽然变量可以在类中作用域。
编译错误期间奇怪的神奇数字:
如果您使用#define
的是那些在预编译时被预处理器替换所以如果您在编译过程中收到错误,那将是令人困惑的,因为错误消息不会引用宏名称而是值并且它会出现一个突然的值,并且在代码中跟踪它会浪费大量时间。
调试问题:
同样出于#2 中提到的相同原因,调试#define
实际上并不会提供太多帮助。
因此,使用const
变量而不是#define
.
它们优于#define
上述所有方面。#define
只有在您需要在代码中进行实际文本替换或定义包含标头保护时才能真正有用的领域。
为什么
#define
在C标准头文件中被广泛使用?
我想到的一个原因是,在 C(与 C++ 不同)中,const
声明不会产生常量表达式。这意味着在 C 标准中引入可变长度数组之前,不能编写如下内容:
const int max_val = 100;
int foos[max_val];
因为在 Cmax_val
中不是编译时间常数,在引入 VLA 的数组下标之前需要编译时间常数。
所以不得不把它写成:
#define MAX_VAL 100
int foos[MAX_VAL];
这可能指的是定义常量的旧 C 方法:
#define MAX_SOMETHING 100
int x = MAX_SOMETHING;
这些常量没有类型化,它们使用字符串替换就地扩展,并且使得调试变得更加困难,因为一旦源代码被编译,就不清楚该定义的来源。
一种更 C++ 的做法是:
const int max_something = 100;
int x = max_something;
由于这是一个强类型值,因此需要进行所有必需的检查和适当的转换。
另一个好处是const
可以将值放入名称空间和类中以用于组织目的。A#define
在范围内是全局的,因此冲突是一个问题,这会导致笨拙的长名称以避免冲突。
之间const
和template
,它允许一种形式的元编程 C 本身不做,需要的场合的数量#define
是相当减少的。但它并没有完全消除,因为没有#import
指令,您仍然需要添加旧的#ifndef __HEADER_FILE_NAME__
守卫以确保不包含两次。
这本书的广泛陈述并不是那么正确 -#define
宏等有它的位置,但对于定义常量,现在使用它不是一个好主意
例如
#define FOO 257
最好在
const int FOO=257;
这允许类型检查,因为使用#define 这变得有点奇怪
char c=FOO;