简体   繁体   English

C ++中#define指令的目的是什么?

[英]What is the purpose of the #define directive in C++?

#define指令的作用是什么?

#define is used to create macros in C and in C++. #define用于在C和C ++中创建宏。 You can read more about it in the C preprocessor documentation . 您可以在C预处理器文档中阅读有关它的更多信息。 The quick answer is that it does a few things: 快速回答是它做了一些事情:

  1. Simple Macros - basically just text replacement. 简单的宏 - 基本上只是文本替换。 Compile time constants are a good example: 编译时间常量是一个很好的例子:

     #define SOME_CONSTANT 12 

    simply replaces the text SOME_CONSTANT with 12 wherever it appears in your code. 只需将文本SOME_CONSTANT替换为12无论它出现在您的代码中。 This sort of macro is often used to provide conditional compilation of code blocks. 这种宏通常用于提供代码块的条件编译。 For example, there might be a header included by each source file in a project with a list of options for the project: 例如,项目中的每个源文件都可能包含一个标头,其中包含项目的选项列表:

     #define OPTION_1 #define OPTION_2 #undef OPTION_3 

    And then code blocks in the project would be wrapped with matching #ifdef / #endif# blocks to enable and disable those options in the finished project. 然后,项目中的代码块将包含匹配的#ifdef / #endif#以在已完成的项目中启用和禁用这些选项。 Using the -D gcc flag would provide similar behaviour. 使用-D gcc标志会提供类似的行为。 There are strong opinions as to whether or not this method is really a good way to provide configuration for an application, however. 但是,对于该方法是否真的是为应用程序提供配置的好方法,存在强烈的意见。

  2. Macros with arguments - allows you to make 'function-like' macros that can take arguments and manipulate them. 带参数的宏 - 允许你制作'类似函数'的宏,它可以接受参数并操纵它们。 For example: 例如:

     #define SQUARE(x) ((x) * (x)) 

    would return the square of the argument as its result; 会返回参数的平方作为结果; be careful about potential order-of-operations or side-effect problems! 注意潜在的操作顺序或副作用问题! The following example: 以下示例:

     int x = SQUARE(3); // becomes int x = ((3) * (3)); 

    will works fine, but something like: 会工作正常,但有点像:

     int y = SQUARE(f()); // becomes int y = ((f()) * (f())); 

    will call f() twice, or even worse: 将调用f()两次,甚至更糟:

     int z = SQUARE(x++); // becomes int z = ((x++) * (x++)); 

    results in undefined behaviour! 导致未定义的行为!

    With some tools, macros with arguments can also be variadic , which can come in handy. 对于某些工具,带参数的宏也可以是可变参数 ,这可以派上用场。

As mentioned below in the comments, overuse of macros, or the development of overly complicated or confusing macros is considered bad style by many - as always, put the readability, maintainability, and debuggability of your code above 'clever' technical tricks. 正如下面评论中所提到的,过度使用宏,或过度复杂或令人困惑的宏的开发被许多人认为是不好的风格 - 一如既往,将代码的可读性,可维护性和可调试性置于'聪明'的技术伎俩之上。

#define (and it's opposite, #undef) can be used to set compiler directives which can then be tested against using #ifndef or #ifdef. #define(与之相反,#undef)可用于设置编译器指令,然后可以使用#ifndef或#ifdef对其进行测试。 This allows for custom behaviors to be defined within the source file. 这允许在源文件中定义自定义行为。 It's used commonly to compile for different environments or debug code. 它通常用于编译不同的环境或调试代码。

An example: 一个例子:

#define DEBUG



#ifdef DEBUG

//perform debug code

#endif

The most common use (by far ) of #define is for include guards: #define最常用的( 到目前为止 )是包括警卫:

// header.hh
#ifndef HEADER_HH_
#define HEADER_HH_

namespace pony {
// ...
}

#endif

Another common use of #define is in creating a configuration file, commonly a config.h file, where we #define macros based on various states and conditions. #define另一个常见用途是创建配置文件,通常是config.h文件,我们根据各种状态和条件#define宏。 Then, in our code we test these macros with #ifdef , #elif defined() etc. to support different compiles for different situations. 然后,在我们的代码中,我们使用#ifdef#elif defined()等来测试这些宏,以支持不同情况下的不同编译。 This is not as solid as the include-guard idiom and you need to be careful here because if the branching is wrong then you can get very obscure compiler errors, or worse, runtime behavior. 这不像include-guard惯用法那么坚固,你需要在这里小心,因为如果分支错误,那么你可以得到非常模糊的编译器错误,或者更糟糕的是,运行时行为。

In general, other than for include guards you need to think through (twice, preferably) about the problem, and see if you can use the compiler rather than the preprocessor to solve it. 通常,除了包含保护之外,您需要仔细考虑(最好两次)关于问题,并查看是否可以使用编译器而不是预处理器来解决它。 The compiler is just smarter than the preprocessor. 编译器比预处理器更聪明。 Not only that, but the compiler can't possibly confuse the preprocessor, whereas the preprocessor most definitely can confuse and mislead the compiler. 不仅如此,编译器不可能混淆预处理器,而预处理器肯定会混淆和误导编译器。

The #define directive has two common uses. #define指令有两个常见用途。

The first one, is control how the compiler will act. 第一个是控制编译器的行为方式。 To do this, we also need #undef, #ifdef and #ifndef. 为此,我们还需要#undef,#ifdef和#ifndef。 (and #endif too...) (和#endif也......)

You can make "compiler logic" this way. 你可以用这种方式制作“编译逻辑”。 A common use is to activate or not a debug portion of the code, like that: 一个常见的用途是激活或不激活代码的调试部分,如下所示:

#ifdef DEBUG

//debug code here

#endif

And you would be able to for example compile the debug code, by writing a #define DEBUG 并且您可以通过编写#define DEBUG来编译调试代码

Another use of this logic stuff, is to avoid double includes... 这个逻辑东西的另一个用途是避免双重包括......

Example, file A, #includes file B and C. But file B also includes C. This likely will result in a compilation error, because "C" exists twice. 例如,文件A,#包括文件B和C.但是文件B也包括C.这可能会导致编译错误,因为“C”存在两次。

The solution is write: 解决方案是:

#ifndef C_FILE_INCLUDED
#define C_FILE_INCLUDED

//the contents of header "c" go here.

#endif

The other use of #define, is make macros. #define的另一个用途是make macros。

The most simple ones, consist of simple substitutions, like: 最简单的,包括简单的替换,如:

#define PI 3.14159265

float perimeter(float radius) {
    return radius*2*PI;
}

or 要么

#define SHOW_ERROR_MESSAGE printf("An serious error happened");

if ( 1 != 1 ) { SHOW_ERROR_MESSAGE }

Then you can also make macros that accept arguments, printf itself usually is a macro, created with a #define in a header file. 然后你也可以创建接受参数的宏,printf本身通常是一个宏,在头文件中用#define创建。

But this should not be done, for two reaons: first, the speed os macros, is the same of using inline, and second, we have c++ templates, that allow more control over functions with variable type. 但是这不应该做,因为两个原因:首先,速度os宏,与使用内联相同,其次,我们有c ++模板,允许更多控制变量类型的函数。 So, the only reason to use macros with arguments, is make strange constructs, that will be hard to understand later, like metaprogrammed stuff... 因此,使用带参数的宏的唯一原因是制作奇怪的结构,以后很难理解,就像元编程的东西......

In C++, #define has very narrow, specialized roles: 在C ++中,#define具有非常狭窄的专业角色:

  • Header guards, described in other answers 标题警卫,在其他答案中描述
  • Interacting with the standard libraries. 与标准库交互。 For instance, #defining WINDOWS_LEAN_AND_MEAN before including windows.h turns off certain often-problematic macros like MAX. 例如,在包含windows.h之前#defining WINDOWS_LEAN_AND_MEAN会关闭像MAX这样经常出问题的宏。
  • Advanced macros involving stringization (ie, macros that print debugging messages) or token-pasting. 涉及字符串化的高级宏(即打印调试消息的宏)或令牌粘贴。

You should avoid using #define for the following purposes. 您应该避免将#define用于以下目的。 The reasons are many; 原因很多; see for instace this FAQ entry . 请参阅此常见问题解答条目

  • Compile-time constants. 编译时常数。 Use const instead. 请改用const
  • Simple macro functions. 简单的宏功能。 Use inline functions and templates instead. 请改用inline函数和模板。

in C or C++ #define allows you to create preprocessor Macros. CC ++中 #define允许您创建预处理器宏。

In the normal C or C++ build process the first thing that happens is that the PreProcessor runs, the preprocessor looks though the source files for preprocessor directives like #define or #include and then performs simple operations with them. 在正常的CC ++构建过程中,首先发生的事情是PreProcessor运行,预处理器查看预处理器指令的源文件,如#define#include ,然后用它们执行简单的操作。

in the case of a #define directive the preprocessor does simple text based substitution. #define指令的情况下,预处理器执行简单的基于文本的替换。

For example if you had the code 例如,如果你有代码

#define PI 3.14159f

float circum = diameter*PI;

the preprocessor would turn it into: 预处理器会把它变成:

float circum = diameter* 3.14159;

by simply replacing the instances of PI with the corresponding text. 只需用相应的文本替换PI的实例即可。 This is only the simplest form of a #define statement for more advanced uses check out this article from MSDN 对于更高级的用途,这只是#define语句的最简单形式,请参阅MSDN中的这篇文章

inCorrectUseOfHashDefine() inCorrectUseOfHashDefine()

{ {

The role of #define is to baffle people who inherit your code with out of the blue statements like: #define的作用是让那些使用蓝色语句继承你代码的人感到困惑,例如:

foreverandever

because of: 因为:

#define foreverandever for(;;)

} }

Please favour constants over #define. 请优先考虑#define上的常量。

It also for setting compiler directives... 它还用于设置编译器指令......

Most things about #defines have been already told, but it's not clear that C++ has better replacements for most of their uses: 关于#defines的大多数事情已经被告知,但是目前尚不清楚C ++在大多数用途中有更好的替代品:

  1. #define to define numerical constants can be easily replaced by a const "variable", that, as a #define, doesn't really exist in the compiled executable. 定义数值常量的#define可以很容易地被const“变量”替换,作为#define,它在编译的可执行文件中并不存在。 AFAIK it can be used in almost all the situations where you could use a #defined numerical constant, including array bounds. AFAIK几乎可以用于所有可以使用#defined数值常量的情况,包括数组边界。 The main advantage for me is that such constants are clearly typed, so there's no need to add casts in the macros "just to be sure", and are scoped, so they can be kept in namespaces/classes/functions, without polluting all the application. 对我来说主要的优点是这些常量显然是类型化的,因​​此不需要在宏中添加强制转换“只是为了确定”,并且是有范围的,因此它们可以保存在命名空间/类/函数中,而不会污染所有的应用。

const int max_array_size=50;
int an_array[max_array_size];
  1. #define to create macros: macros can often be replaced by templates; #define来创建宏:宏通常可以被模板替换; for example, the dreaded MAX macro 例如,可怕的MAX宏

#define MAX(a,b)    ((a)<(b)?(b):(a))

, which has several downsides (eg repeated arguments evaluation, inevitable inline expansion), can be replaced by the max function 有几个缺点(例如重复参数评估,不可避免的内联扩展),可以用max函数替换

template<typename T> T & max(T & a, T & b)
{
    return a<b?b:a;
}

which can be type-safe (in this version the two arguments are forced to be of the same type), can be expanded inline as well as not (it's compiler decision), evaluates the arguments just once (when it's called), and is scoped. 这可以是类型安全的(在这个版本中,两个参数被强制为相同的类型),可以内联扩展,也可以不扩展(它的编译器决定),只评估一次参数(当它被调用时),并且作用域。 A more detailed explanation can be found here . 可在此处找到更详细的说明。

Still, macros must still be used for include guards, to create some kind of strange language extensions that expand to more line of code, that have unbalanced parenthesis, etc. 仍然,宏仍然必须用于包含保护,创建某种奇怪的语言扩展,扩展到更多的代码行,具有不平衡的括号,等等。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM