你所遇到的最糟糕的实际宏/预处理器滥用是什么(请不要回答显然的IOCCC*哈哈*)?
如果有一个有趣的小片段或故事,请添加进来。目标是教授一些东西,而不是总是告诉人们“永远不要使用宏”。
p.s .:我以前使用过宏……但通常我最终会摆脱它们,当我有了“真正的”解决方案时(即使真正的解决方案是内联的,因此类似于宏)。
奖励:给出一个示例,其中宏确实比非宏解决方案更好。
相关问题:C++宏何时有利?
你所遇到的最糟糕的实际宏/预处理器滥用是什么(请不要回答显然的IOCCC*哈哈*)?
如果有一个有趣的小片段或故事,请添加进来。目标是教授一些东西,而不是总是告诉人们“永远不要使用宏”。
p.s .:我以前使用过宏……但通常我最终会摆脱它们,当我有了“真正的”解决方案时(即使真正的解决方案是内联的,因此类似于宏)。
奖励:给出一个示例,其中宏确实比非宏解决方案更好。
相关问题:C++宏何时有利?
#if PROGRAMA
.
.
if(...)
{
.
.
.
#else
.
.
if(...)
{
.
.
.
#endif
}
是的, 他一次关闭了两个打开的窗口。
#define PROCESS_AND_RETURN(X) \
X.process(); \
// Important: Return only after invoking virtual method process() \
return X
我还要补充一个让我逐渐感到烦恼的问题:
#define ARRAYSIZE(x) (sizeof(x)/sizeof((x)[0]))
如果他们做对了的话,我见过所有可能排列的括号版本。我还见过它在同一个头文件中被定义了两次。
主要是针对Windows(虽然我认为其他操作系统SDK也有类似的东西),几乎每个人都似乎觉得需要在项目的头文件中定义这个宏,我不明白为什么。
WinNT.h(由Windows.h包含)定义了一个非常好的版本,如果你传递指针类型而不是数组,则执行一些模板魔术使其产生编译时错误。
当然,如果您正在构建C程序,它会回退到我上面写的内容,但我仍然不会无缘无故地重新定义SDK默认具有的东西。
#define DIM(x) (sizeof x / sizeof * x)
让我省了很多打字的时间。 - Jamie
#define ARGLIST(...) __VA_ARGS__
#define CPPTYPELESSARG(typelessParams) thisptr, typelessParams
#define CPPTYPEDARG(typedParams) void* thisptr, typedParams
#define CPPTYPELESSNOARG thisptr
#define CPPTYPEDNOARG void* thisptr
#define CPPHOOKBODY(hookName, params) void *thisptr; \
__asm { mov thisptr, ecx } \
return On##hookName ( params );
#define CHOOKBODY(hookName, typelessParams) return On##hookName( typelessParams );
#define CPPHOOK(InjectHookRef, importLib, importFunc, hookName, returnType, typedParams, typelessParams) \
HOOKIMPL(InjectHookRef, importLib, importFunc, hookName, returnType, CPPTYPEDARG(typedParams), typelessParams, \
typedParams, __thiscall, __stdcall, CPPHOOKBODY(hookName, CPPTYPELESSARG(typelessParams)))
#define CPPHOOKNOARG(InjectHookRef, importLib, importFunc, hookName, returnType, typedParams, typelessParams) \
HOOKIMPL(InjectHookRef, importLib, importFunc, hookName, returnType, CPPTYPEDNOARG, typelessParams, \
typedParams, __thiscall, __stdcall, CPPHOOKBODY(hookName, CPPTYPELESSNOARG))
#define CDECLHOOK(InjectHookRef, importLib, importFunc, hookName, returnType, typedParams, typelessParams) \
HOOKIMPL(InjectHookRef, importLib, importFunc, hookName, returnType, typedParams, typelessParams, \
typedParams, __cdecl, __cdecl, CHOOKBODY(hookName, typelessParams))
#define CDECLFUNC(name, address, returnType, args) \
typedef returnType (__cdecl *name##Ptr)(args); \
name##Ptr name = (name##Ptr) address;
#define CPPFUNC(name, address, returnType, args) \
typedef returnType (__thiscall *name##Ptr)(void* thisptr, args); \
name##Ptr name = (name##Ptr) address;
#define STDFUNC(name, address, returnType, args) \
typedef returnType (__stdcall *name##Ptr)(args); \
name##Ptr name = (name##Ptr) address;
#define STDHOOK(InjectHookRef, importLib, importFunc, hookName, returnType, typedParams, typelessParams) \
HOOKIMPL(InjectHookRef, importLib, importFunc, hookName, returnType, typedParams, typelessParams, \
typedParams, __stdcall, __stdcall, CHOOKBODY(hookName, ARGLIST(typelessParams)))
#define HOOKIMPL(InjectHookRef, importLib, importFunc, hookName, returnType, typedParams, typelessParams, hookParams, fnPtrCall, hookCall, hookBody) \
typedef returnType (fnPtrCall *##hookName##OrigPtr )( typedParams ); \
class hookName : public IHook \
{ \
public: \
typedef hookName##OrigPtr func_type; \
private: \
static void* m_origFunction; \
static bool m_bModifyImport; \
static std::string m_lib; \
static std::string m_importFunc; \
static std::string m_sHookName; \
static returnType hookCall hookName##FnHook ( hookParams ) \
{ \
hookBody \
} \
static bool ImplIsModifyImport() { return hookName::m_bModifyImport; } \
static void ImplSetModifyImport(bool bModify) { hookName::m_bModifyImport = bModify; } \
static const std::string& ImplGetLibName() { return hookName::m_lib; } \
static const std::string& ImplGetImportFunctionName() { return hookName::m_importFunc; } \
static void ImplSetOriginalAddress(void* fn) { hookName::m_origFunction = fn; } \
static void* ImplGetOriginalAddress() { return hookName::m_origFunction; } \
static returnType On##hookName ( typedParams ); \
static void* ImplGetNewAddress() { return hookName::##hookName##FnHook; } \
static const std::string& ImplGetHookName() { return hookName::m_sHookName; } \
public: \
hookName() \
{ \
InjectHookRef.AddHook((IHook*)this); \
hookName::m_lib = importLib; \
hookName::m_importFunc = importFunc; \
hookName::m_sHookName = #hookName; \
hookName::m_origFunction = NULL; \
hookName::m_bModifyImport = true; \
} \
virtual bool IsModifyImport() const { return hookName::ImplIsModifyImport(); } \
virtual void SetModifyImport(bool bModify) { hookName::ImplSetModifyImport(bModify); } \
virtual const std::string& GetHookName() const { return hookName::ImplGetHookName(); } \
virtual const std::string& GetLibName() const { return hookName::ImplGetLibName(); } \
virtual const std::string& GetImportFunctionName() const { return hookName::ImplGetImportFunctionName(); } \
virtual void* GetOriginalAddress() const { return hookName::ImplGetOriginalAddress(); } \
virtual void* GetNewAddress() const { return hookName::ImplGetNewAddress(); } \
virtual void SetOriginalAddress(void* fn) { hookName::m_origFunction = fn; } \
static func_type GetTypedOriginalAddress() { return reinterpret_cast(hookName::m_origFunction); } \
}; \
void* hookName::m_origFunction = NULL; \
bool hookName::m_bModifyImport = false; \
std::string hookName::m_lib; \
std::string hookName::m_importFunc; \
std::string hookName::m_sHookName; \
static hookName g##hookName##Inst;
这反过来使我能够做到这一点:
CPPHOOK(gIH, "SimEngine.dll", "?AddEntity@Player@@UAEXPAVEntity@@@Z", PlayerAddEntity, void, void* ent, ent);
/* 当引擎调用Player::AddEntity(entity)时调用 */ void PlayerAddEntity::OnPlayerAddEntity(void *thisptr, void *ent) { unsigned int id = getPlayerID(thisptr);
gIH.GetLog()->Info("Player %d adding entity %s.",
getPlayerID(thisptr), getEntityName(ent));
gPlayers[id] = thisptr;
/*if( id == 2 && gPlayers[1] && gPlayers[2] )
EntitySetOwner::GetTypedOriginalAddress() (ent, gPlayers[1]);*/
//gEnts[ent] = Entity(ent, Vector3f());
PlayerAddEntity::GetTypedOriginalAddress() (thisptr, ent);
}
#define EP_STATUS CASTLING][(BOARD_FILES-2)
#define HOLDINGS_SET CASTLING][(BOARD_FILES-1)
当我第一次接触C语言中的宏时,我被搞糊涂了好几天。下面是我面临的情况。我想对于C专家来说,这很容易理解并且非常高效,然而对于我来说,要弄清楚到底发生了什么,就意味着需要将所有不同的宏粘贴在一起,直到整个函数可以被查看。这难道不是一个好习惯吗?!为什么不能使用普通的函数呢?!
#define AST_LIST_MOVE_CURRENT(newhead, field) do { \
typeof ((newhead)->first) __list_cur = __new_prev; \
AST_LIST_REMOVE_CURRENT(field); \
AST_LIST_INSERT_TAIL((newhead), __list_cur, field); \
} while (0)
好的宏定义:(虽然我个人不喜欢使用这种语法所需的双括号;我更喜欢可变参数宏(仅限C99)或类似于PRINTF_0,PRINTF_1等的东西,取决于参数数量)
#ifdef DEBUG
#define PRINTF(x) printf x
#else
#define PRINTF(x)
#endif
对于非调试版本,它可以减少代码大小/执行时间(前者比后者更多)。此外,它还可以防止泄漏调试文本字符串,这可能会带来一些安全风险。
一位前雇主发现现代Unix系统上没有实现BASIC-PLUS,因此他们尝试使用C预处理器宏重新实现它:
#define IF if(
#define THEN ) {
#define ENDIF }
#define GOTO goto L
...etc.
(请提供更多需要翻译的内容)与雷蒙德的发泄有关的是以下可怕的宏(在我看来,当然):
#define CALL_AND_CHECK(func, arg) \
int result = func(arg); \
if(0 != result) \
{ \
sys.exit(-1); \
} \
我对使用宏的实践还比较新,使用了这个宏,但是我预期传递给它的函数会失败。而且我在后台线程中执行它,所以我的整个应用程序为什么会“崩溃”困扰了我好几天。
顺便说一下,如果当时有std::tr1::function,我就可以省下一周的时间了!