哪些用例需要 #define 没有令牌字符串
What use cases necessitate #define without a token-string?
我之前在学习C时遇到过#define
预处理器指令,然后在我读的一些代码中也遇到了它。但是,除了使用它来明确替换常量和定义宏之外,我还没有真正承担过在没有"主体"或标记字符串的情况下使用它的特殊情况。
以这一行为例:
#define OCSTR(X)
就这样!这个或更好的用是什么,什么时候需要这种使用#define
?
在两种情况下使用。 第一个也是最常见的涉及条件编译:
#ifndef XYZ
#define XYZ
// ...
#endif
你自己肯定用过这个包括警卫,但它也可以用于系统依赖关系等内容:
#ifdef WIN32
// Windows specific code here...
#endif
(在这种情况下,WIN32 更有可能在命令行上定义,但它也可以在"config.hpp"
文件中定义。这通常会仅涉及类似对象的宏(没有参数列表或括号(。
第二个是有条件编译的结果。 东西喜欢:
#ifdef DEBUG
#define TEST(X) text(X)
#else
#define TEST(X)
#endif
这允许编写以下内容:
TEST(X);
如果定义了DEBUG
,它将调用该函数,如果它不是。
这样的宏通常成对出现在条件#ifdef
中,如下所示:
#ifdef _DEBUG
#define OCSTR(X)
#else
#define OCSTR(X) SOME_TOKENS_HERE
#endif
再比如,
#ifdef __cplusplus
#define NAMESPACE_BEGIN(X) namespace X {
#define NAMESPACE_END }
#else
#define NAMESPACE_BEGIN(X)
#define NAMESPACE_END
#endif
我最近挖出的一个奇怪的案例来回答一个问题,结果证明它本质上只是评论。 有问题的代码如下所示:
void CLASS functionName(){
//
//
//
}
我发现这只是一个空#define
,作者选择记录该函数访问项目中的全局变量:
C++ 语法:void CLASS functionName((?
所以和它说/* CLASS */
并没有太大区别,除了不允许像/* CLAAS */
这样的错别字......也许还有其他一些小好处(?
我同意每一个答案,但我想指出一件微不足道的小事。
作为一个C纯粹主义者,我从小就断言每个#define
都应该是一个表达,所以,即使这是通常的做法:
#define WHATEVER
并进行测试
#ifdef WHATEVER
我认为写起来总是更好的:
#define WHATEVER (1)
此外#debug
宏应为表达式:
#define DEBUG (xxx) (whatever you want for debugging, value)
通过这种方式,您可以完全避免滥用#macros
并防止出现令人讨厌的问题(尤其是在 1000 万行 C 项目中(
当您可能想要使某些函数静音时,可以使用此功能。例如,在调试模式下,您希望打印一些调试语句,而在生产代码中,您希望省略它们:
#ifdef DEBUG
#define PRINT(X) printf("%s", X)
#else
#define PRINT(X) // <----- silently removed
#endif
用法:
void foo ()
{
PRINT("foo() startsn");
...
}
#define
宏在预处理期间只是简单地替换为它们的替换文本。如果没有替换文本,则...他们被什么都没有取代!所以这个源代码:
#define FOO(x)
print(FOO(hello world));
将被预处理成这样:
print();
这对于摆脱您不想要的东西很有用,例如,assert()
.它主要在条件情况下有用,但在某些情况下,有一个非空的身体。
正如您在上面的响应中看到的那样,它在调试代码时很有用。
#ifdef DEBUG
#define debug(msg) fputs(__FILE__ ":" (__LINE__) " - " msg, stderr)
#else
#define debug(msg)
#endif
因此,当您调试时,该函数将打印行号和文件名,以便您知道是否存在错误。如果你不调试,它只会产生没有输出
这样的事情有很多用途。
例如,一种是宏在不同的版本中具有不同的行为。例如,如果你想要调试消息,你可以有这样的东西:
#ifdef _DEBUG
#define DEBUG_LOG(X, ...) however_you_want_to_print_it
#else
#define DEBUG_LOG(X, ...) // nothing
#endif
另一个用途可能是根据您的系统自定义头文件。这是来自我在 Linux 中实现的 OpenGL 标头:
#if !defined(OPENSTEP) && (defined(__WIN32__) && !defined(__CYGWIN__))
# if defined(__MINGW32__) && defined(GL_NO_STDCALL) || defined(UNDER_CE) /* The generated DLLs by MingW with STDCALL are not compatible with the ones done by Microsoft's compilers */
# define GLAPIENTRY
# else
# define GLAPIENTRY __stdcall
# endif
#elif defined(__CYGWIN__) && defined(USE_OPENGL32) /* use native windows opengl32 */
# define GLAPIENTRY __stdcall
#elif defined(__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__) >= 303
# define GLAPIENTRY
#endif /* WIN32 && !CYGWIN */
#ifndef GLAPIENTRY
#define GLAPIENTRY
#endif
并用于标头声明,例如:
GLAPI void GLAPIENTRY glClearIndex( GLfloat c );
GLAPI void GLAPIENTRY glClearColor( GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha );
GLAPI void GLAPIENTRY glClear( GLbitfield mask );
...
(我删除了GLAPI
部分(
所以你明白了,在某些情况下使用而在其他情况下不使用的宏可以定义为这些情况下的某些内容,而在其他情况下则不定义
任何内容。其他情况可能如下:
如果宏不采用参数,则可能只是声明某些情况。一个著名的示例是保护头文件。另一个例子是这样的
#define USING_SOME_LIB
以后可以这样用:
#ifdef USING_SOME_LIB
...
#else
...
#endif
可能是宏在某个阶段被用来做某事(例如日志(,但在发布时,所有者认为日志不再有用,只是删除了宏的内容,使其变为空。但是不建议这样做,请使用我在答案开头提到的方法。
最后,它可能只是为了更多的解释,例如你可以说
#define DONT_CALL_IF_LIB_NOT_INITIALIZED
你写的函数如下:
void init(void);
void do_something(int x) DONT_CALL_IF_LIB_NOT_INITIALIZED;
虽然最后一种情况有点荒谬,但在这种情况下是有道理的:
#define IN
#define OUT
void function(IN char *a, OUT char *b);
- 是否可以在多行字符串文本中使用 C/C++ 预处理器令牌
- 如何在没有运算符>>的情况下从字符串流返回下一个令牌?
- 如何将字符串作为预处理器令牌传递
- 如何使用向量字符串令牌构建表达树
- C 令牌字符串并存储在向量中
- 在C 中的令牌字符串中区分操作数和操作员
- 为什么我的字符串令牌在我的C 野牛程序中最终减少时会获得新线
- 使用令牌解析字符串并分配给变量
- 将字符串拆分为令牌-不包含操作系统特定的函数
- C++:函数返回静态库中的字符串给出错误:在令牌之前':'预期的"="、""、";"、'asm'或'__attribute__'
- 当捕获boost::bad_exical_cast时,我可以访问要强制转换的字符串/令牌吗
- 如何避免在转换字符串令牌流时重复istringstream构造
- C++预处理器能否判断令牌是否为字符串
- C++:仅使用 STL 从字符串中提取令牌
- 如何使 Boost.Spirit.Lex 令牌值成为匹配序列的子字符串(最好通过正则表达式匹配组)
- 如何使"strtok function"一次使用多个令牌字符串? 函数指针会解决这个问题吗?
- C++ 基于/使用(提升)正则表达式拆分字符串以查找令牌
- 分析boost中的令牌时基础字符串的索引
- 获取令牌之间的子字符串
- 哪些用例需要 #define 没有令牌字符串