限制#define
标签范围并避免不必要的令牌冲突的正确策略是什么?
在以下配置中:
MAIN.C
# include "Utility_1.h"
# include "Utility_2.h"
# include "Utility_3.h"
VOID Main() { ... }
Utility_1.h
# define ZERO "Zero"
# define ONE "One"
BOOL Utility_1(); // Uses- ZERO:"Zero" & ONE:"One"
Utility_2.h
# define ZERO '0'
# define ONE '1'
BOOL Utility_2(); // Uses- ZERO:'0' & ONE:'1'
Utility_3.h
const UINT ZERO = 0;
const UINT ONE = 1;
BOOL Utility_3(); // Uses- ZERO:0 & ONE:1
注意: Utility _1
,Utility_2
和Utility_3
已经独立编写
错误:宏重新定义和令牌冲突
另外,最令人担忧的是:编译器没有说明什么替换了令牌替换的内容
{编辑} 注意:这是一般性问题,所以请:不建议enum
或const
即。做什么时候:我必须使用#define
& _请在下面评论我提出的解决方案.. __
答案 0 :(得分:12)
正确的策略是不使用
#define ZERO '0'
#define ONE '1'
完全没有。如果您需要常量值,请使用,在这种情况下,使用const char
包装在命名空间中。
答案 1 :(得分:6)
#define
没有与C ++代码对应的范围;你无法限制它。它们是天真的文本替换宏。想象一下,当我用grep替换文本时,我该如何限制范围?“
你应该尽可能地避免使用它们,而不是使用真正的C ++类型。
正确使用宏几乎可以通过命名约定来解决这个问题。如果宏被命名为对象,它应 一个对象(而不是宏)。问题解决了。如果宏被命名为函数(例如动词),它应该 一个函数。
这适用于文字值,变量,表达式,语句......这些都不应该是宏。这些都是可以咬你的地方。
在其他情况下,当你使用某种类型的语法助手时,你的宏名称几乎肯定不符合其他任何命名约定。所以问题几乎消失了。但最重要的是,当命名冲突时,需要成为宏的宏将导致编译错误。
答案 2 :(得分:6)
一些选项:
对宏与普通标识符使用不同的大小写约定。
const UINT Zero = 0;
通过在宏中添加模块名称伪造命名空间:
#define UTIL_ZERO '0' #define UTIL_ONE '1'
在可用的地方(C ++),沟通宏并使用真正的命名空间:
namespace util { const char ZERO = '0'; const char ONE = '1'; };
答案 3 :(得分:5)
限制#define范围并避免无法解决的令牌冲突的正确策略是什么。
除非确实需要,否则请避免使用宏。在C ++中,通常可以使用常量变量和内联函数。它们具有键入的优点,并且可以在命名空间,类或代码块中进行范围限定。在C中,需要更频繁地使用宏,但在引入之前要仔细考虑替代方案。
使用命名约定来明确哪些符号是宏,哪些是语言级别的标识符。保留ALL_CAPITALS
名称以供独占使用宏是很常见的;如果你这样做,那么宏只能与其他宏发生冲突。这也使人们更加关注更容易出错的代码部分。
在每个宏名称上包含一个“伪命名空间”前缀,以便来自不同库/模块/任何内容的宏和具有不同目的的宏不太可能发生冲突。因此,如果您正在设计一个想要为数字零定义字符常量的狡猾库,请将其命名为DODGY_DIGIT_ZERO
。只有ZERO
可能意味着许多事情,并且很可能与由不同的狡猾的图书馆定义的零价值常数冲突。
答案 4 :(得分:4)
有两种类型的#define
宏:
仅在单个文件中需要的一个。我们称他们为Private #defines
例如。 PI 3.14
在这种情况下:
按照标准做法:正确的策略是将#define
标签 - 仅放在实施中,即。 c
,文件而不是标题 h
文件。
多个文件需要的另一个:让我们称这些Shared #defines
为
例如。 EXIT_CODE 0x0BAD
在这种情况下:
只在标题 #define
文件中放置此类常用h
标签。
另外,尝试使用False NameSpaces
或类似约定命名标签唯一,例如在标签前添加MACRO_
,例如:#define MACRO_PI 3.14
,以便发生碰撞概率减少
答案 5 :(得分:1)
限制#define范围并避免无法解决的令牌冲突的正确策略是什么。
一些简单的规则:
#include
警卫。我没有这么做,但最好将预处理器符号保持在最低限度。
const static
变量而不是命名浮点常量。
const UINT ZERO = 0; // Programmer not aware of what's inside Utility.h
首先,如果程序员没有找到Utility.h中的内容,为什么程序员会使用#include
语句?显然UINT
来自某个地方......
其次,程序员通过命名变量ZERO
来提出问题。保留预处理器符号的所有上限名称。如果您遵守规则,则无需知道Utility.h中的内容。简单地假设Utility.h遵循规则。将该变量的名称设为zero
。
答案 6 :(得分:0)
我认为你真的只需知道你包括的是什么。这就像试图包含windows.h然后声明一个名为WM_KEYDOWN的变量。如果你有碰撞,你应该重命名你的变量,或者(有点黑客),#undef它。
答案 7 :(得分:-2)
C是一种结构化编程语言。它有其局限性。这就是面向对象系统排在第一位的原因。在C中似乎没有其他方法,然后了解你的头文件的变量以_VARIABLE表示法开头的内容,以便它有更少的机会重写。
in header file
_ZERO 0
in regular file
ZERO 0
答案 8 :(得分:-4)
#define
标签 - 仅放在实施中,即。 c
,文件此外,所有#define
都可以单独放入另一个文件中 - 例如:Utility_2_Def.h
(很像微软的WinError.h
: Win32 api函数的错误代码定义)
<强>间接费用:强>
<强>收益:强>
ZERO
:0
,'0'
或"Zero"
关于您使用它的位置<强> Utility_2.h 强>
BOOL Utility_2();
<强> Utility_2_Def.h 强>
# define ZERO '0'
# define ONE '1'
<强> Utility_2.c 强>
# include "Utility_2.h"
# include "Utility_2_Def.h"
BOOL Utility_2()
{
...
}