简体   繁体   English

什么是预处理器宏有用?

[英]What are preprocessor macros good for?

After reading another question about the use of macros, I wondered: What are they good for? 阅读另一个问题关于使用宏后,我在想: 它们是什么好?

One thing I don't see replaced by any other language construct very soon is in diminishing the number of related words you need to type in the following: 我很快就会看到被其他语言构造取代的一件事是减少你需要在下面输入的相关单词的数量:

void log_type( const bool value ) { std::cout << "bool: " << value; }
void log_type( const int value ) { std::cout << "int: " << value; }
...
void log_type( const char  value ) { std::cout << "char: "  << value; }
void log_type( const double  value ) { std::cout << "int: "  << value; }
void log_type( const float  value ) { std::cout << "float: "  << value; }

as opposed to 而不是

#define LOGFN( T ) void log_type( const T value ) { std::cout << #T ## ": " << value; }
LOGFN( int )
LOGFN( bool )
...
LOGFN( char )
LOGFN( double )
LOGFN( float )

Any other 'irreplaceables'? 还有其他“不可替代的”吗?

EDIT: trying to summarize the reasons-why encountered in the answers; 编辑:试图总结原因 - 为什么在答案中遇到; since that's what I was interested in. Mainly because I have a feeling that most of them are due to us still programming in raw text files in, still, poorly supporting environments. 因为那是我感兴趣的东西。主要是因为我有一种感觉,他们中的大部分是由于我们仍然在原始文本文件中编程,仍然是支持不佳的环境。

  • flexibility of code-to-be compiled (eg #ifdef DEBUG , platform issues) (SadSido, Catalin, Goz) 代码编译的灵活性(例如#ifdef DEBUG ,平台问题)(SadSido,Catalin,Goz)
  • debug purposes (eg __LINE__, __TIME__ ); 调试目的(例如__LINE__, __TIME__ ); I also put 'stringifying' under this reason (SadSido, Jla3ep, Jason S) 我也根据这个原因设置'字符串'(SadSido,Jla3ep,Jason S)
  • replacing eg PHP's require vs. include feature ( #pragma once ) (SadSido, Catalin) 替换例如PHP的requireinclude功能( #pragma once )(SadSido,Catalin)
  • readability enhancement by replacing complicated code (eg MESSAGEMAP , BOOST_FOREACH ) (SadSido, fnieto) 通过替换复杂的代码来增强可读性(例如MESSAGEMAPBOOST_FOREACH )(SadSido,fnieto)
  • DRY principle (Jason S) 干原则(杰森S)
  • an inline replacement (Matthias Wandel, Robert S. Barnes) 内联替换(Matthias Wandel,Robert S. Barnes)
  • stringifying (Jason S) stringifying(杰森S)
  • compile different code under different conditions ( #ifdef __DEBUG__ ); 在不同的条件下编译不同的代码( #ifdef __DEBUG__ );
  • guards to include each header once for each translation unit ( #pragma once ); 保护每个翻译单元包含一次标题( #pragma once );
  • __FILE__ and __LINE__ - replaced by the current file name and current line; __FILE____LINE__ - 由当前文件名和当前行替换;
  • structuring the code to make it more readable (ex: BEGIN_MESSAGE_MAP() ); 构造代码以使其更具可读性(例如: BEGIN_MESSAGE_MAP() );

See interesting macro discussion at gotw here: 在这里看到有趣的宏观讨论:

http://www.gotw.ca/gotw/032.htm http://www.gotw.ca/gotw/032.htm

http://www.gotw.ca/gotw/077.htm http://www.gotw.ca/gotw/077.htm

Most useful - header file guarding: 最有用的 - 头文件保护:

#ifndef MY_HEADER_GUARD
#define MY_HEADER_GUARD

// Header file content.

#endif 

Later add [ Windows only ] 稍后添加[ 仅限Windows ]

Exporting classes to DLL: 将类导出到DLL:

#ifdef EXPORT_MY_LIB
#define    MY_API __declspec( dllexport)
#else
#define    MY_API __declspec( dllimport)
#endif

Sample class: 样本类:

class MY_API MyClass { ... };

platform specific sections. 平台特定部分。

ie

#ifdef WINDOWS
#include "WindowsImplementation.h"
#elif defined( LINUX )
#include "LinuxImplementation.h"
#else
#error Platform undefined.
#endif

I've posted this before, but of course cannot now find it. 我以前发过这个,但当然现在找不到了。 If you want to access the __FILE__ and __LINE__ macros, then another macro is by far the most convenient way to go - for example: 如果你想访问__FILE____LINE__宏,那么另一个宏是目前最方便的方式 - 例如:

#define ATHROW(msg)                                         \
{                                                           \
    std::ostringstream os;                                  \
    os << msg;                                              \
    throw ALib::Exception( os.str(), __LINE__, __FILE__ );  \
}

For doing cool magic tricks like in BOOST_FOREACH , injecting variables into an ambit. 为了做一些像BOOST_FOREACH这样的酷魔术技巧, 将变量注入一个范围。

BOOST_FOREACH( char c, "Hello, world!" )
{
   ... use char variable c here ...
}   // c's scope ends here
// if there's an outer c defined, its scope resumes here

For don't-repeat-yourself (DRY) reasons. 因为不重复自己(DRY)的原因。 Things that involve repeated constructs at compile-time which cannot be abstracted away in other methods (templates or what have you). 在编译时涉及重复构造的事情,不能在其他方法(模板或你有什么)中抽象出来。 If you are finding you're repeating the same code constructs 20 times, that's a potential source of human error -- which hopefully can be abstracted away using templates but sometimes not. 如果您发现重复相同的代码构造20次,那么这是人为错误的潜在根源 - 希望可以使用模板将其抽象出去,但有时却不会。 It's always a balance between the advantages of seeing raw code that can be type-checked and reviewed clearly, vs. the advantages of using macros for arbitrary substitution patterns (that generally can't be checked by automatic programming tools). 它总是在看到可以进行类型检查和清晰审查的原始代码的优势与使用宏来实现任意替换模式(通常无法通过自动编程工具检查)的优势之间取得平衡。

Stringifying and concatenation (the # and ## preprocessor patterns) can't be performed by templates. 字符串化和连接(#和##预处理器模式)不能由模板执行。

Of course, at some point you may be better off using a tool (whether custom or off-the-shelf) for automatic code generation. 当然,在某些时候,您可能最好使用工具(无论是自定义还是现成的)来自动生成代码。

Modern languages take the philosophy that needing a proeprocessor ins a sign of a missing language feature, so they define all kinds of language features that the preprocessor took care of very simply back in the old K&R style C. 现代语言采用的理念是需要一个支持处理器的语言功能缺失的标志,因此它们定义了预处理器在旧的K&R风格C中非常简单地处理的各种语言功能。

Your code example above could be simplified via an inline function, for example. 例如,上面的代码示例可以通过内联函数进行简化。

Personally, the most indispensable aspect of a preprocessor is to make it clear that some things are done compile time right in the source code. 就个人而言,预处理器中最不可或缺的方面是清楚地表明某些事情是在源代码中编译完成的。 The java approach of eliminating dead code paths at compile time is just not as obvious when reading the code. 在编译时消除死代码路径的java方法在读取代码时并不那么明显。

One of their uses is basically as a poor mans ( inlined ) template function. 他们的一个用途基本上是一个穷人(内联)模板功能。

For example : 例如

#define MIN(X,Y) ((X) < (Y) ? : (X) : (Y))

This allows you to generate a custom MIN function for any types supporting these operators which is effectively inline at the point of useage. 这允许您为支持这些运算符的任何类型生成自定义MIN函数,这些函数在使用时实际上是内联的。 Of course there is no type checking and it's easy to end up with weird syntax errors or incorrect behavior if you don't get the parens just right. 当然没有类型检查,如果你没有恰到好处的话,很容易就会出现奇怪的语法错误或不正确的行为。

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

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