C++ 预处理器宏有什么用?
在阅读了关于宏使用的另一个问题后,我想知道:它们有什么好处 有一件事我看不出会很快被任何其他语言结构所取代,那就是减少需要键入以下内容的相关单词的数量:C++ 预处理器宏有什么用?,c++,macros,C++,Macros,在阅读了关于宏使用的另一个问题后,我想知道:它们有什么好处 有一件事我看不出会很快被任何其他语言结构所取代,那就是减少需要键入以下内容的相关单词的数量: void log_type( const bool value ) { std::cout << "bool: " << value; } void log_type( const int value ) { std::cout << "int: " << value; } ... void lo
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; }
void log_type(const bool value){std::cout最有用-头文件保护:
#ifndef MY_HEADER_GUARD
#define MY_HEADER_GUARD
// Header file content.
#endif
以后添加[仅限Windows]
将类导出到DLL:
#ifdef EXPORT_MY_LIB
#define MY_API __declspec( dllexport)
#else
#define MY_API __declspec( dllimport)
#endif
示例类:
class MY_API MyClass { ... };
- 在不同的条件下编译不同的代码(
#ifdef uu_u调试u
)
- 为每个翻译单元包含一次标题(
#pragma once
)
\uuuuuuuuu文件
和\uuuuu行
替换为当前文件名和当前行
- 对代码进行结构化以使其更具可读性(例如:
BEGIN\u MESSAGE\u MAP()
)
请参见gotw上有趣的宏讨论:
平台特定部分
即
我以前发布过这个,但现在当然找不到了。如果您想访问\uuuuu文件\uuuuuuuu
和\uuuuuu行\uuuuuuuu
宏,那么另一个宏是目前为止最方便的方式-例如:
#define ATHROW(msg) \
{ \
std::ostringstream os; \
os << msg; \
throw ALib::Exception( os.str(), __LINE__, __FILE__ ); \
}
#定义ATHROW(msg)\
{ \
std::ostringstream os\
现代语言的哲学思想是,需要前置处理器就意味着缺少语言功能,因此它们定义了各种语言功能,而在旧的K&R风格C中,前置处理器非常简单地处理了这些功能
例如,可以通过内联函数简化上面的代码示例
就个人而言,预处理器最不可或缺的方面是明确一些事情是在源代码的编译时正确完成的。在编译时消除死代码路径的java方法在阅读代码时并不那么明显。对于像中这样的酷魔术来说,在某种范围内
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
它们的一个用途基本上是作为穷人(内联)模板函数
:
定义最小值(X,Y)((X)<(Y)?:(X):(Y))
这允许您为支持这些运算符的任何类型生成一个自定义的MIN函数,该函数在使用时有效地内联。当然,没有类型检查,如果没有正确地获得paren,很容易出现奇怪的语法错误或错误行为。用于“请勿重复”(DRY)原因。编译时涉及重复构造的东西,不能在其他方法(模板或其他)中抽象掉。如果您发现重复相同的代码构造20次,这可能是人为错误的一个潜在来源——希望可以使用模板将其抽象掉,但有时不能。这始终是看到可以进行类型检查和清晰查看的原始代码的优势与使用宏进行套利的优势之间的平衡y替换模式(通常无法通过自动编程工具进行检查)
串接和连接(和预处理器模式)不能由模板执行
当然,在某些情况下,使用工具(无论是定制的还是现成的)可能会更好对于自动代码生成。我认为这应该由构建系统来处理,而不是由语言来处理。@ xFutl我从未见过一个构建系统这样做,但是听起来很有趣。你在C或C++项目中有没有这样的例子?谢谢。他认为他指的是VisualStudio的“从构建中排除”。功能性。我在这些方面遇到的问题是,你最终可能会在多个不同的编译器之间工作,等等。我想这一切都可以通过一个生成文件来完成,但我曾经参与过需要在GCC、Visual Studio和Code Warrior(即PS2、X-Box&PC和Wii)下编译的项目。在这些情况下它是可行的,但执行上述操作要容易得多。应通过分层体系结构实现可移植性。一方面有一个没有ifdef的接口,另一方面有此接口的实现。在某些情况下(例如Windows/Unix),最好使用生成环境来选择正确的文件(如果私有部分需要某些特定于平台的类型,也可以使用平台版本的接口),有很多共同点,处理条件编译是有意义的。@Glen-我有时会看到这样做,例如,有一个'platform.h'头-一个用于Windows,一个用于Linux,在不同的目录中,构建系统将根据目标平台使用不同的包含文件路径。因此C源文件只是一个eds至#包括“platform.h”但是,我个人更倾向于使用< <代码> >如果选择“差异”,则很难看到“构建系统”的配置,尤其是比平台目标更复杂的选项。GCC支持导出。我指的是Windows环境,而不是Visual C++。无需在每个类型名中键入两次即可添加它。@Jla3ep,甚至不包括guards?#pragma once
是一个非标准但得到广泛支持的预处理器指令,旨在使当前源文件在一次编译中只包含一次。广泛?这里四个目标中有三个不支持。好的,对我来说,广泛足够了。cl和g++支持它。第一个变量对我来说更清晰。确实如此。这意味着它是一个坏例子。我将尝试想出一个更好的例子。这不应该是一个宏,这应该是一个模板函数,如template void log_type(const T value){…}
。很长一段时间以来,宏的这种用法已经被另一种语言结构所取代。@Jla3ep:如果有两个函数,则更清楚。如果有30个函数
#define ATHROW(msg) \
{ \
std::ostringstream os; \
os << msg; \
throw ALib::Exception( os.str(), __LINE__, __FILE__ ); \
}
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
#define MIN(X,Y) ((X) < (Y) ? : (X) : (Y))