什么用例需要 #define 而不带标记字符串?

发布于 2024-12-07 13:37:27 字数 237 浏览 0 评论 0原文

我之前在学习 C 时遇到过 #define 预处理器指令,然后在我阅读的一些代码中也遇到过它。但除了使用它来明确替换常量和定义宏之外,我还没有真正理解它在没有“主体”或标记字符串的情况下使用的特殊情况。

以这句话为例:

#define OCSTR(X)

就像那样!什么时候需要使用 #define ,这个或更好的用途是什么?

I have encountered the #define pre-processor directive before while learning C, and then also encountered it in some code I read. But apart from using it to definite substitutions for constants and to define macros, I've not really understook the special case where it is used without a "body" or token-string.

Take for example this line:

#define OCSTR(X)

Just like that! What could be the use of this or better, when is this use of #define necessary?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

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

评论(8

没有心的人 2024-12-14 13:37:27

这在两种情况下使用。第一个也是最常见的涉及
条件编译:

#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,它将调用该函数,如果定义了,则不执行任何操作
不是。

This is used in two cases. The first and most frequent involves
conditional compilation:

#ifndef XYZ
#define XYZ
//  ...
#endif

You've surely used this yourself for include guards, but it can also be
used for things like system dependencies:

#ifdef WIN32
//  Windows specific code here...
#endif

(In this case, WIN32 is more likely defined on the command line, but it
could also be defined in a "config.hpp" file.) This would normally
only involve object-like macros (without an argument list or
parentheses).

The second would be a result of conditional compilation. Something
like:

#ifdef DEBUG
#define TEST(X) text(X)
#else
#define TEST(X)
#endif

That allows writing things like:

TEST(X);

which will call the function if DEBUG is defined, and do nothing if it
isn't.

冷情妓 2024-12-14 13:37:27

此类宏通常成对出现在条件 #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

Such macro usually appears in pair and inside conditional #ifdef as:

#ifdef _DEBUG
   #define OCSTR(X)
#else
   #define OCSTR(X)  SOME_TOKENS_HERE
#endif

Another example,

#ifdef __cplusplus
   #define NAMESPACE_BEGIN(X) namespace X {
   #define NAMESPACE_END }
#else
   #define NAMESPACE_BEGIN(X) 
   #define NAMESPACE_END
#endif
冧九 2024-12-14 13:37:27

我最近为了回答一个问题而挖掘的一个奇怪的案例,结果证明它本质上只是评论。有问题的代码如下所示:

void CLASS functionName(){
  //
  //
  //
}

我发现它只是一个空的 #define,作者选择它来记录该函数访问项目中的全局变量:

C++ 语法:void CLASS functionName()?

所以与 if 没有什么不同说 /* CLASS */,除了不允许像 /* CLAAS */ 这样的拼写错误......也许还有其他一些小好处(?)

One odd case that I recently dug up to answer a question turned out to be simply commentary in nature. The code in question looked like:

void CLASS functionName(){
  //
  //
  //
}

I discovered it was just an empty #define, which the author had chosen to document that the function accessed global variables in the project:

C++ syntax: void CLASS functionName()?

So not really that different from if it said /* CLASS */, except not allowing typos like /* CLAAS */...some other small benefits perhaps (?)

东走西顾 2024-12-14 13:37:27

我同意每个答案,但我想指出一件小事。

作为一名 C 纯粹主义者,我从小就坚信“每个 #define 都应该是一个表达式”,因此,即使使用:

#define WHATEVER

并使用以下命令进行测试

#ifdef WHATEVER

是常见的做法,我认为这样写总是更好:

#define WHATEVER (1)

另外,#debug 宏应该是表达式:

#define DEBUG (xxx) (whatever you want for debugging, value)

这样,您就可以完全避免误用#macros,并防止出现严重问题(尤其是在 1000 万行 C 项目中)

I agree with every answer, but I'd like to point out a small trivial thing.

Being a C purist I've grown up with the assertion that EACH AND EVERY #define should be an expression, so, even if it's common practice using:

#define WHATEVER

and test it with

#ifdef WHATEVER

I think it's always better writing:

#define WHATEVER (1)

also #debug macros shall be expressions:

#define DEBUG (xxx) (whatever you want for debugging, value)

In this way, you are completely safe from misuse of #macros and prevents nasty problems (especially in a 10 million line C project)

半世晨晓 2024-12-14 13:37:27

当您想要静音某些功能时可以使用此功能。例如,在调试模式下,您想要打印一些调试语句,而在生产代码中,您想要省略它们:

#ifdef DEBUG
#define PRINT(X) printf("%s", X)
#else
#define PRINT(X)  // <----- silently removed
#endif

用法:

void foo ()
{
  PRINT("foo() starts\n");
  ...
}

This can be used when you may want to silent some function. For example in debug mode you want to print some debug statements and in production code you want to omit them:

#ifdef DEBUG
#define PRINT(X) printf("%s", X)
#else
#define PRINT(X)  // <----- silently removed
#endif

Usage:

void foo ()
{
  PRINT("foo() starts\n");
  ...
}
断念 2024-12-14 13:37:27

#define 宏在预处理过程中被简单地替换为替换文本。如果没有替换文本,那么......它们就不会被替换!所以这个源代码:

#define FOO(x)

print(FOO(hello world));

将被预处理成这样:

print();

这对于摆脱你不想要的东西很有用,比如,assert()。它主要在条件情况下有用,但在某些情况下存在非空体。

#define macros are simply replaced, literally, by their replacement text during preprocessing. If there is no replacement text, then ... they're replaced by nothing! So this source code:

#define FOO(x)

print(FOO(hello world));

will be preprocessed into just this:

print();

This can be useful to get rid of things you don't want, like, say, assert(). It's mainly useful in conditional situations, where under some conditions there's a non-empty body, though.

昔梦 2024-12-14 13:37:27

正如您在上面的响应中看到的,它在调试代码时非常有用。

#ifdef DEBUG
#define debug(msg) fputs(__FILE__ ":" (__LINE__) " - " msg, stderr)
#else
#define debug(msg)
#endif

因此,当您进行调试时,该函数将打印行号和文件名,以便您知道是否存在错误。如果您不进行调试,它将不会产生任何输出

As you can see in the above responses, it can be useful when debugging your code.

#ifdef DEBUG
#define debug(msg) fputs(__FILE__ ":" (__LINE__) " - " msg, stderr)
#else
#define debug(msg)
#endif

So, when you are debugging, the function will print the line number and file name so you know if there is an error. And if you are not debugging, it will just produce no output

浅黛梨妆こ 2024-12-14 13:37:27

这样的东西有很多用途。

例如,一种是宏在不同的构建中具有不同的行为。例如,如果您想要调试消息,您可以有这样的内容:

#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);

There are many uses for such a thing.

For example, one is for the macro to have different behavior in different builds. For example, if you want debug messages, you could have something like this:

#ifdef _DEBUG
  #define DEBUG_LOG(X, ...) however_you_want_to_print_it
#else
  #define DEBUG_LOG(X, ...) // nothing
#endif

Another use could be to customize your header file based on your system. This is from my mesa-implemented OpenGL header in linux:

#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

And used in header declarations like:

GLAPI void GLAPIENTRY glClearIndex( GLfloat c );

GLAPI void GLAPIENTRY glClearColor( GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha );

GLAPI void GLAPIENTRY glClear( GLbitfield mask );

...

(I removed the part for GLAPI)

So you get the picture, a macro that is used in some cases and not used in other cases could be defined to something on those cases and nothing to those other cases.

Other cases could be as follows:

If the macro doesn't take parameters, it could be just to declare some case. A famous example is to guard header files. Another example would be something like this

#define USING_SOME_LIB

and later could be used like this:

#ifdef USING_SOME_LIB
...
#else
...
#endif

Could be that the macro was used at some stage to do something (for example log), but then on release the owner decided the log is not useful anymore and simply removed the contents of the macro so it becomes empty. This is not recommended though, use the method I mentioned in the very beginning of the answer.

Finally, it could be there just for more explanation, for example you can say

#define DONT_CALL_IF_LIB_NOT_INITIALIZED

and you write functions like:

void init(void);
void do_something(int x) DONT_CALL_IF_LIB_NOT_INITIALIZED;

Although this last case is a bit absurd, but it would make sense in such a case:

#define IN
#define OUT

void function(IN char *a, OUT char *b);
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文