启用C++替代运算符致MSVC内联汇编编译错误的解决办法
这个问题的根源其实是<ciso646>头文件的宏定义和MSVC内联汇编的指令名冲突了——<ciso646>会把and、or这些词预定义成&&、||的宏,而MSVC处理内联汇编时会先过一遍C++预处理器,导致汇编里的and被替换成&&,自然触发语法错误。
下面给你几个不用把汇编指令全大写的解决办法,按推荐程度排序:
1. 用#pragma push_macro/pop_macro临时管理宏定义(最推荐)
这个方法既解决汇编的冲突问题,又不会破坏代码其他地方对<ciso646>替代运算符的使用,安全性最高。原理是先保存当前and/or的宏定义,临时取消它们,写完汇编后再恢复。
修改你的示例代码如下:
__declspec (naked) Unit* __fastcall D2CLIENT_GetClientUnit(int nGUID, DWORD dwType) { // 临时保存并取消and/or的宏定义 #pragma push_macro("and") #undef and #pragma push_macro("or") #undef or __asm { push edx mov eax, ecx shl edx, 0x09 and eax, 0x7F add edx, [D2CLIENT_6FBBA608] call D2CLIENT_6FB54E20 retn } // 恢复宏定义,不影响后续代码使用替代运算符 #pragma pop_macro("or") #pragma pop_macro("and") }
2. 仅在需要的代码块中使用<ciso646>
如果你的项目里只有部分代码需要用and/or这些替代运算符,不要全局包含<ciso646>,只在特定的源文件或函数里包含它。这样汇编所在的文件/函数不包含这个头,自然就不会有宏冲突问题。
比如:
// 仅在这个函数里用替代运算符 #include <ciso646> void someFunction() { bool a = true and false; // 正常使用替代运算符 } // 汇编所在的函数不包含<ciso646> __declspec (naked) Unit* __fastcall D2CLIENT_GetClientUnit(int nGUID, DWORD dwType) { __asm { // 汇编指令正常写小写and/or,无冲突 push edx mov eax, ecx shl edx, 0x09 and eax, 0x7F add edx, [D2CLIENT_6FBBA608] call D2CLIENT_6FB54E20 retn } }
3. 将汇编指令写成字符串形式
MSVC的__asm支持用字符串来编写汇编代码,而预处理器不会处理字符串内部的内容,所以and/or不会被替换成宏。这种方法适合不想改动宏定义的场景,只是可读性稍差一点:
__declspec (naked) Unit* __fastcall D2CLIENT_GetClientUnit(int nGUID, DWORD dwType) { __asm { "push edx\n" "mov eax, ecx\n" "shl edx, 0x09\n" "and eax, 0x7F\n" "add edx, [D2CLIENT_6FBBA608]\n" "call D2CLIENT_6FB54E20\n" "retn" } }
注意每个汇编行末尾要加\n来分隔指令,确保汇编器能正确解析。
4. 局部取消宏定义(简单但需注意影响范围)
如果汇编函数之后不需要使用and/or替代运算符,可以直接在汇编前#undef掉这两个宏:
__declspec (naked) Unit* __fastcall D2CLIENT_GetClientUnit(int nGUID, DWORD dwType) { #undef and #undef or __asm { push edx mov eax, ecx shl edx, 0x09 and eax, 0x7F add edx, [D2CLIENT_6FBBA608] call D2CLIENT_6FB54E20 retn } }
这个方法简单,但如果后续代码还需要用替代运算符,就会失效,所以不如第一种方法安全。
内容的提问来源于stack exchange,提问作者Verv
相关产品推荐
相关产品推荐

