为什么要为预处理器指令烦恼呢?
这个问题可能看起来相当基本,但来自工程(非计算机科学)背景,我不确定某些 C++ 代码中的 '#
片段是什么。
快速搜索让我找到了关于预处理器指令的简洁、解释良好的 cplusplus 教程页面。
但为什么要费心预处理器指令的概念呢?是否不可能编写可以为常量赋值、定义子例程/函数/宏和处理错误的等效代码?
我想我最终想知道什么时候使用这样的预处理器指令是好的实践,什么时候不是。
This question may seem rather basic, but coming from an engineering (non computer-science) background, I was unsure about what the snippets of '#
's were in some C++ code.
A quick search led me to the concise, well-explained cplusplus tutorial page on preprocessor directives.
But why bother with the concept of preprocessor directives at all? Is it not possible to write equivalent code that can assign values to constants, define subroutines/function/macros and handle errors?
I guess I ultimately want to know when it is good practice to use such preprocessor directives, and when it is not.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(14)
当您需要执行实际应用程序范围之外的操作时,可以使用预处理器指令。例如,您将看到预处理完成,以包含或不包含基于正在构建的可执行文件的体系结构的代码。例如:
预处理器指令还用于保护包含,以便类/函数等不会被定义多次。
另一个用途是在代码和库中嵌入版本控制。
在 Makefile 中,您有以下内容:
在代码中,您有
You use preprocessor directives when you need to do something outside of the scope of the actual application. For instance, you'll see preprocessing done to include or not include code based on the architecture the executable is being built for. For example:
Preprocessor directives are also used to guard includes so that classes/functions etc. are not defined more than once.
Another use is for embedding versioning inside of code and libraries.
In the Makefile you have something along the lines of:
While in the code you have
答案 1:条件代码必须根据其运行的计算机类型而变化。
答案 2:启用和禁用编译时看到的语言扩展和兼容性功能。
预处理器来自C,那里有很多东西你无法表达。好的 C++ 代码比 C 代码有更少的理由使用它,但遗憾的是它并不是完全无用。
Answer 1: conditional code that has to vary depending on what sort of computer it works on.
Answer 2: enabling and disabling language extensions and compatibility features seen at compile time.
The preprocessor came from C, where there were many thing you could not express. Good C++ code finds less reasons to use it than C code did, but sadly it's not quite useless.
预处理发生在代码编译之前。它适用于如下情况,
显然包括您希望在编译时而不是运行时完成的头文件。我们不能用变量来做到这一点。
另一方面。对于 C++,这是一种很好的做法,并且强烈鼓励替换如下例所示的常量表达式
。原因是您可以获得正确的类型转换和数据类型处理。
也不
是很好,因为你可以写
The preprocessor will Replace it with:
这显然不会给出预期的结果。
相反,MAX 应该是一个函数(而不是宏)。如果它是一个函数,它还可以在参数中提供类型。
我见过预处理器用于各种有趣的事情。就像语言关键字声明一样。在这种情况下,它可以帮助提高可读性。
简而言之,将预处理器用于编译类型中必须发生的事情,例如条件包含指令。避免将其用作常量。避免使用宏,而是尽可能使用函数。
Preprocessing occurs before the code is compiled. It's appropriate in cases like the following
Obviously including header files you want done at compilation time not runtime. We can't do this with variables.
On the other hand. With C++ it is good practice and greatly encouraged to replace constant expressions like the following example
The reason is that you get proper typecasting and datatype handling.
Also
Is not very nice because you can write
The preprocessor would replace that with:
Which is clearly not going to give the intended result.
Instead, MAX should be a function (not a macro). If it's a function it can also provide the type in the parameter.
I have seen the preprocessor used for all sorts of interesting things. Like language keyword declaration. It can aid in readability in this case.
In short, use the preprocessor for things that must happen at compile type such as conditional includes directives. Avoid using it for constants. Avoid macros and instead use functions where possible.
因为预处理器指令在构建时执行,而您编写的代码将在运行时执行。因此,预处理器指令有效地使您能够以编程方式修改源代码。
请注意,C 预处理器对于此类事情来说是一个相当粗糙的机制; C++ 的模板系统为代码的编译时构建提供了更强大的框架。其他语言具有更强大的元编程功能(例如 Lisp 的宏系统)。
Because preprocessor directives get executed at build time, while code you write will get executed at run time. So preprocessor directives effectively give you the ability to modify your source code programmatically.
Note that the C preprocessor is a rather crude mechanism for this kind of thing; C++'s template system provides a much more powerful framework for compile-time construction of code. Other languages have even more powerful metaprogramming features (for example, Lisp's macro system).
它最常用于两件事,如果没有它,组织将变得更加困难:
It is used most frequently for two things which will be harder to organize without it:
许多编程语言都具有元编程功能,您可以在其中为编译器编写代码,而不是运行时环境。
例如,在 C++ 中,我们有模板,它允许我们指示编译器根据类型甚至编译时常量生成某些代码。 Lisp 也许是具有高级元编程功能的语言中最著名的例子。
C 预处理器指令/宏只是“元编程”的另一种形式,尽管它比其他语言中的形式相对粗糙。预处理器指令指示编译器在编译时执行某些操作,例如忽略某些平台上的某些代码,或者查找代码中的字符串并将其替换为另一个字符串。在代码编译完成后,这是不可能在运行时完成的。
因此本质上,C 预处理器是“元编程”或编译器编程的早期形式。
Many programming languages have meta-programming facilities, where you write code for the compiler to follow, rather than the runtime environment.
For example, in C++, we have templates which allow us to instruct the compiler to generate certain code based on a type, or even a compile-time constant. Lisp is perhaps the most famous example of a language with advanced meta-programming facilities.
C preprocessor directives/macros are just another form of "meta-programming", albeit a relatively cruder form than is available in other languages. Preprocessor directives instruct the compiler to do certain things at compile time, such as to ignore certain code on certain platforms, or to find and replace a string in the code with another string. This would be impossible to do at runtime, after your code is already compiled.
So essentially, the C-preprocessor is an early form of "meta-programming", or compiler-programming.
这里有一些历史:C++ 是从 C 发展而来的,C 比 C++ 更需要预处理器。例如,要在 C++ 中定义常量,您可以编写类似
const int foo = 4;
的内容,而不是粗略的#define FOO 4
C 等值。不幸的是,太多人将他们的预处理器习惯从 C 带到了 C++。C++ 中预处理器有几种合理的用途。对头文件使用
#include
是非常有必要的。它对于条件编译也很有用,包括标头包含保护,因此可以多次#include
标头(例如在不同的标头中)并仅处理一次。assert
语句实际上是一个预处理器宏,并且有一些类似的用途。除此之外,C++ 中的合法用途实在是太少了。
A bit of history here: C++ was developed from C, which needed the preprocessor a lot more than C++ did. For example, to define a constant in C++, you'd write something like
const int foo = 4;
, for example, instead of#define FOO 4
which is the rough C equivalent. Unfortunately, too many people brought their preprocessor habits from C to C++.There are several reasonable uses of the preprocessor in C++. Using
#include
for header files is pretty much necessary. It's also useful for conditional compilation, including header include guards, so it's possible to#include
a header several times (such as in different headers) and have it processed only once. Theassert
statement is actually a preprocessor macro, and there are a few similar uses.Aside from those, there are darn few legitimate uses in C++.
通常,不应使用预处理器指令。遗憾的是,有时您必须在 C 和 C++ 中这样做。
C 最初定义该语言的方式是,如果不使用预处理器,您实际上无法用它做任何严肃的事情。该语言没有其他内置支持来创建模块化程序、常量、内联代码或进行通用编程。
C++ 消除了大部分这些问题,但该功能仍然存在,因此它仍然被使用。 (有趣的是,不是模块化。我们仍然坚持使用
#include
),如果您想与在类似抽象级别构建的语言进行比较,以执行没有预处理器的类似任务,去看看 Ada。
Generally, preprocessor directives should not be used. Sadly, sometimes you have to in C and C++.
C originally defined the language in such a way that you really couldn't do anything serious with it without using the preprocessor. The language had no other built in support for creating modular programs, constants, inlined code, or to do generic programming.
C++ gets rid of most of these issues but the facility is still there, so it still gets used. (Interestingly, not the modularization one. We're still stuck with
#include
),If you want to compare with a language built at a similar-level of abstraction for similar tasks that does not have a preprocessor, go take a look at Ada.
不,实际上在所有情况下都不可能没有预处理器。我最喜欢的宏之一是
如果没有宏,我会在最终的可执行文件中浪费(可能很多)空间
而且您必须意识到,C/C++ 没有任何类型的包类型
require
或其他此类系统。因此,如果没有预处理器,就无法防止代码重复。 (不能包含头文件)No, it actually is not possible to get by without the preprocessor in all cases. One of my favorite macros is
Without macros, I would have (possibly a lot) space wasted in the final executable
And also you must realize, C/C++ doesn't have any sort of package type
require
or other such system. So without the preprocessor, there is no way of preventing code-duplication. (header files can't be included)它在 C++ 中的使用率非常低,该语言的功能是为了避免与预处理器相关的问题而创建的。
在一般的 C++ 源代码中,这通常被视为不好的做法 - 特别是当有办法使用其他语言功能来做到这一点时。有些事情(即平台/构建相关程序和生成程序)需要它。简而言之,通常会有一个可扩展的替代品。 (例如常量定义为枚举,或内联模板而不是宏)。如果您发现自己正在使用一个并且不确定,那么只需询问/搜索是否有更好的方法在 C++ 中声明
this_code_snippet
,而不需要预处理器。Its use is very low in C++, features of the language were created to avoid problems associated with the preprocessor.
In general C++ sources, it is often seen as poor practice - particularly when there is a mean to do it using other language features. It is required for some things (i.e. platform/build dependent programs and generative programs). In short, there's usually a replacement which scales well. (such as constant define as enum, or inline templates instead of macros). If you find yourself using one and you are not sure, then just ask/search if there is a better way to declare
this_code_snippet
in C++, without the preprocessor.它是从 C++ 中获取一些反射功能的替代品。
对于生成具有相同名称的变量和字符串非常有用。
It's a better-than-nothing substitute to get some reflection capabilities out of C++.
Very useful to generate variables and strings with the same names.
此处回答。
Answered here.
C 预处理器执行许多任务,其中一些任务(但不是全部)在 C++ 中有更好的替代方案。如果 C++ 有更好的替代方案,请使用它。这些替代方案包括模板、内联和 const 变量(矛盾修饰法,但这就是标准对它们的称呼)来代替 #define 宏。
然而,有些事情是您不想没有或根本不能没有的;例如,#include 是必不可少的,并且在针对多个平台或配置进行编码时,条件编译仍然有用(尽管在所有情况下都应谨慎使用)。
在某些情况下,通过#pragma 控制的编译器特定扩展可能是不可避免的。
The C preprocessor performs a number of tasks, some but not all of which have better alternatives in C++. Where C++ has a better alternative use it. Those alternatives include templates, inlining, and
const
variables (an oxymoron, but that is what the standard calls them) in place of #define macros.However there are few things that you would not want to do without or simply cannot do without;
#include
for example is essential, and when coding for multiple platforms or configurations, conditional compilation remains useful (although should be used sparingly in all cases).Compiler specific extensions controlled via
#pragma
may be unavoidable in some cases.与其他人不同,我对预处理器指令没有大问题。唯一的问题是使用预处理器定义在 C 中比 C++ 中效果更好。例如:Win32、OpenGL、zip 库、jni 和许多其他 C 库使用预处理器指令。例如:Win32 有“OPAQUE”和“TRANSPARENT”,它们被传递给它们的函数 SetBkMode(HDC,int);现在想象一下想要使用这些词中的任何一个是多么容易。你不能,因为 C 预处理器不关心命名空间。为什么没有 Cpp 预处理器。
但我知道适合工作的工具。
Unlike everybody else, I don't have a big problem with preprocessor directives. The only thing is that using preprocessor defines works better in C than C++. Eg: Win32, OpenGL, zip libraries, jni and many other c libraries use preprocessor directives. Eg: Win32 has "OPAQUE" and "TRANSPARENT" which is passed to their function SetBkMode(HDC,int); Now imagine how easily it is to want to use any of those words. You can't, because C preprocessor doesn't care about namespace. Why isn't there a Cpp preprocessor.
But I know the right tool for job.