基于预处理器宏的代码会产生C2400错误

时间:2010-06-29 03:10:20

标签: c++ visual-studio assembly c-preprocessor

#define CANCEL_COMMON_DIALOG_HOOK(name)  \
void __declspec(naked) ##name##CancelCommonDialogHook(void)  \
{  \
    __asm  \
    {  \
        add     esp, [k##name##CancelCommonDialogStackOffset]  \
        jz      RESTORE  \
        jmp     [k##name##CancelCommonDialogNewFileRetnAddr]  \
    RESTORE:  \
        pushad  \
        call    DoSavePluginCommonDialogHook  \
        test    eax, eax  \
        jnz     REMOVE  \
        popad  \
        jmp     [k##name##CancelCommonDialogRestoreRetnAddr]  \
    REMOVE:  \
        popad  \
        jmp     [k##name##CancelCommonDialogRemoveRetnAddr]      \
    }  \
}

使用上面的宏会导致编译器抛出此错误:

  

错误C2400:内联汇编语法   '第二操作数'中的错误;发现   '恢复'

我做错了什么?

编辑:

void __declspec(naked) #name##CancelCommonDialogHook(void)               \ 
{                                                                        \
    __asm   add     esp, [k##name##CancelCommonDialogStackOffset]        \
    __asm   jz      RESTORE                                              \
    __asm   jmp     [k##name##CancelCommonDialogNewFileRetnAddr]         \
    RESTORE:                                                             \
    __asm   pushad                                                       \
    __asm   call    DoSavePluginCommonDialogHook                         \
    __asm   test    eax, eax                                             \
    __asm   jnz     REMOVE                                               \
    __asm   popad                                                        \
    __asm   jmp     [k##name##CancelCommonDialogRestoreRetnAddr]         \
    REMOVE:                                                              \
    __asm   popad                                                        \
    __asm   jmp     [k##name##CancelCommonDialogRemoveRetnAddr]          \
}

以上代码也不起作用:

  

错误C2447:'{':缺少功能   header(旧式正式列表?)错误   C2014:必须启动预处理程序命令   作为第一个非白色空间

4 个答案:

答案 0 :(得分:0)

至少在我最后一次尝试时,你无法在VC ++中的内联汇编块中创建标签。使用C风格的标签虽然有效:

void __declspec(naked) ##name##CancelCommonDialogHook(void)  \
{  \
    __asm  \
    {  \
        add     esp, [k##name##CancelCommonDialogStackOffset]  \
        jz      RESTORE  \
        jmp     [k##name##CancelCommonDialogNewFileRetnAddr]  \
    }           \
    RESTORE:    \
    _asm {      \
        pushad  \
        call    DoSavePluginCommonDialogHook  \
        test    eax, eax  \
        jnz     REMOVE  \
        popad  \
        jmp     [k##name##CancelCommonDialogRestoreRetnAddr]  \
    }          \
    REMOVE:    \
    __asm {    \
        popad  \
        jmp     [k##name##CancelCommonDialogRemoveRetnAddr]      \
    }  \
}

我还没有在VC ++中编写任何内联汇编很长一段时间,所以我不能保证它会起作用,但我猜这是一个非常公平的机会。

答案 1 :(得分:0)

我一直没有电脑访问权限,所以希望你已经解决了这个问题。我认为问题是使用“\”来结束该行实际上告诉C预处理器将下一行与该行合并。请参阅this page上的评论3和行拼接here。这适用于大多数C语句,但对于汇编更有问题,因为新行是它如何定义语句。

我可以想到解决方案的两种方法。首先是找到类似C的“;”可以在装配中用作法定分隔符,我不知道是否存在这样的东西。第二种方法是将所有内容包装在单独的__asm语句中。采取第二种方法,如下:

void __declspec(naked) ##name##CancelCommonDialogHook(void)          
{                                                                    
    __asm{add     esp, [k##name##CancelCommonDialogStackOffset]}      \
    __asm{jz      RESTORE}                                            \
    __asm{jmp     [k##name##CancelCommonDialogNewFileRetnAddr]}       \
    RESTORE:                                                          \
    __asm{pushad}                                                     \
    __asm{call    DoSavePluginCommonDialogHook}                       \
    __asm{test    eax, eax}                                           \
    __asm{jnz     REMOVE}                                             \
    __asm{popad}                                                      \
    __asm{jmp     [k##name##CancelCommonDialogRestoreRetnAddr]}       \
    REMOVE:                                                           \
    __asm{popad}                                                      \
    __asm{jmp     [k##name##CancelCommonDialogRemoveRetnAddr]}        \
}

注意:我已将标签留在asm语句之外,因为:

  1. 我认为你可以
  2. 我不确定__asm
  3. 中定义的标签的范围规则

答案 2 :(得分:0)

只是一个疯狂的猜测:宏会将所有文本扩展为一行,最后是add esp, [k...] jz RESTORE jmp k...。也许在每个汇编指令的末尾添加分号会很有帮助。

该假设的一个指示是错误发生在你的第二个“线”上。第一个是好的,但第二个将合并到第一个,所以这是编译器混淆的第一次机会。如果错误发生在某个地方,那可能不是这样。

答案 3 :(得分:0)

通过将函数体包含在另一个范围内来修复它。