C++ 宏什么时候有用?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/96196/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
When are C++ macros beneficial?
提问by Motti
The Cpreprocessor is justifiably feared and shunned by the C++ community. In-lined functions, consts and templates are usually a safer and superior alternative to a #define
.
该ç预处理器有理由担心和C ++社区避之唯恐不及。内联函数、常量和模板通常是#define
.
The following macro:
下面的宏:
#define SUCCEEDED(hr) ((HRESULT)(hr) >= 0)
is in no way superior to the type safe:
绝不优于类型安全:
inline bool succeeded(int hr) { return hr >= 0; }
But macros do have their place, please list the uses you find for macros that you can'tdo without the preprocessor.
但是宏确实有其一席之地,请列出您发现的宏的用途,这些用途在没有预处理器的情况下无法实现。
Please put each use-cases in a seperate answer so it can be voted up and if you know of how to achieve one of the answers without the preprosessor point out how in that answer's comments.
请将每个用例放在一个单独的答案中,以便可以对其进行投票,如果您知道如何在没有预教授的情况下获得其中一个答案,请在该答案的评论中指出如何。
采纳答案by Frank Szczerba
As wrappers for debug functions, to automatically pass things like __FILE__
, __LINE__
, etc:
作为包装的调试功能,以自动传递之类的东西__FILE__
,__LINE__
等:
#ifdef ( DEBUG )
#define M_DebugLog( msg ) std::cout << __FILE__ << ":" << __LINE__ << ": " << msg
#else
#define M_DebugLog( msg )
#endif
回答by jdmichal
Methods must always be complete, compilable code; macros may be code fragments. Thus you can define a foreach macro:
方法必须始终是完整的、可编译的代码;宏可能是代码片段。因此你可以定义一个 foreach 宏:
#define foreach(list, index) for(index = 0; index < list.size(); index++)
And use it as thus:
并按如下方式使用它:
foreach(cookies, i)
printf("Cookie: %s", cookies[i]);
Since C++11, this is superseded by the range-based for loop.
从 C++11 开始,这被基于范围的 for 循环取代。
回答by Kevin
Header file guards necessitate macros.
头文件保护需要宏。
Are there any other areas that necessitatemacros? Not many (if any).
还有其他需要宏的区域吗?不多(如果有的话)。
Are there any other situations that benefit from macros? YES!!!
还有其他情况可以从宏中受益吗?是的!!!
One place I use macros is with very repetitive code. For example, when wrapping C++ code to be used with other interfaces (.NET, COM, Python, etc...), I need to catch different types of exceptions. Here's how I do that:
我使用宏的一个地方是非常重复的代码。例如,当包装 C++ 代码以与其他接口(.NET、COM、Python 等)一起使用时,我需要捕获不同类型的异常。这是我如何做到的:
#define HANDLE_EXCEPTIONS \
catch (::mylib::exception& e) { \
throw gcnew MyDotNetLib::Exception(e); \
} \
catch (::std::exception& e) { \
throw gcnew MyDotNetLib::Exception(e, __LINE__, __FILE__); \
} \
catch (...) { \
throw gcnew MyDotNetLib::UnknownException(__LINE__, __FILE__); \
}
I have to put these catches in every wrapper function. Rather than type out the full catch blocks each time, I just type:
我必须将这些捕获放在每个包装器函数中。我没有每次都输入完整的 catch 块,而是输入:
void Foo()
{
try {
::mylib::Foo()
}
HANDLE_EXCEPTIONS
}
This also makes maintenance easier. If I ever have to add a new exception type, there's only one place I need to add it.
这也使维护更容易。如果我不得不添加新的异常类型,只需要在一个地方添加它。
There are other useful examples too: many of which include the __FILE__
and __LINE__
preprocessor macros.
还有其他有用的示例:其中许多包括__FILE__
和__LINE__
预处理器宏。
Anyway, macros are very useful when used correctly. Macros are not evil -- their misuseis evil.
无论如何,宏在正确使用时非常有用。宏不是邪恶的——它们的滥用是邪恶的。
回答by David Thornley
Mostly:
大多:
- Include guards
- Conditional compilation
- Reporting (predefined macros like
__LINE__
and__FILE__
) - (rarely) Duplicating repetitive code patterns.
- In your competitor's code.
- 包括守卫
- 条件编译
- 报告(预定义的宏,如
__LINE__
和__FILE__
) - (很少)复制重复的代码模式。
- 在您的竞争对手的代码中。
回答by Andrew Stein
Inside conditional compilation, to overcome issues of differences between compilers:
在条件编译中,为了克服编译器之间的差异问题:
#ifdef ARE_WE_ON_WIN32
#define close(parm1) _close (parm1)
#define rmdir(parm1) _rmdir (parm1)
#define mkdir(parm1, parm2) _mkdir (parm1)
#define access(parm1, parm2) _access(parm1, parm2)
#define create(parm1, parm2) _creat (parm1, parm2)
#define unlink(parm1) _unlink(parm1)
#endif
回答by Motti
When you want to make a string out of an expression, the best example for this is assert
(#x
turns the value of x
to a string).
当您想从表达式中生成字符串时,最好的示例是assert
(#x
将 的值x
转换为字符串)。
#define ASSERT_THROW(condition) \
if (!(condition)) \
throw std::exception(#condition " is false");
回答by Motti
String constants are sometimes better defined as macros since you can do more with string literals than with a const char *
.
字符串常量有时更好地定义为宏,因为与使用const char *
.
e.g. String literals can be easily concatenated.
例如,字符串文字可以很容易地连接起来。
#define BASE_HKEY "Software\Microsoft\Internet Explorer\"
// Now we can concat with other literals
RegOpenKey(HKEY_CURRENT_USER, BASE_HKEY "Settings", &settings);
RegOpenKey(HKEY_CURRENT_USER, BASE_HKEY "TypedURLs", &URLs);
If a const char *
were used then some sort of string class would have to be used to perform the concatenation at runtime:
如果使用了 aconst char *
则必须使用某种字符串类来在运行时执行连接:
const char* BaseHkey = "Software\Microsoft\Internet Explorer\";
RegOpenKey(HKEY_CURRENT_USER, (string(BaseHkey) + "Settings").c_str(), &settings);
RegOpenKey(HKEY_CURRENT_USER, (string(BaseHkey) + "TypedURLs").c_str(), &URLs);
回答by Motti
When you want to change the program flow (return
, break
and continue
) code in a function behaves differently than code that is actually inlined in the function.
当您想要更改程序流(return
,break
和continue
)时,函数中的代码与函数中实际内联的代码的行为不同。
#define ASSERT_RETURN(condition, ret_val) \
if (!(condition)) { \
assert(false && #condition); \
return ret_val; }
// should really be in a do { } while(false) but that's another discussion.
回答by Kena
The obvious include guards
显而易见的包括守卫
#ifndef MYHEADER_H
#define MYHEADER_H
...
#endif
回答by 1800 INFORMATION
You can't perform short-circuiting of function call arguments using a regular function call. For example:
您不能使用常规函数调用来执行函数调用参数的短路。例如:
#define andm(a, b) (a) && (b)
bool andf(bool a, bool b) { return a && b; }
andm(x, y) // short circuits the operator so if x is false, y would not be evaluated
andf(x, y) // y will always be evaluated