预处理器是否盲目地取代了定义?

时间:2011-12-09 11:01:04

标签: c++ c-preprocessor

我有一个名为SendMessage的成员函数的类。项目中不存在名为SendMessageA的成员函数。 项目是多字节的,所以我有一个定义

#define SendMessage SendMessageA

如果我在该课程的某个地方致电SendMessage,我的项目会调用SendMessage还是SendMessageA

如果替换是由预处理器完成的,则项目不应编译。对吗? 但我在转储中看到SendMessageA被调用...结束eip寄存器不在任何VAD中

修改

更具体的问题:预处理器是否盲目地替换了定义?或首先检查班级中的匹配?

4 个答案:

答案 0 :(得分:3)

预处理器在编译之前运行您的代码。 因此任何SendMessage都将转换为SendMessageA。然后,编译器将查找名为SendMessageA的函数并调用它。

答案 1 :(得分:2)

预处理器用作文本宏处理器。如果定义了宏,则所有出现的宏都将替换为它的定义。

#define blabla some_real_stuff

struct blabla /* blabla will be replaced with some_real_stuff */
{
   void method();
};

int main()
{
   some_real_stuff x;
   x.method();
}

答案 2 :(得分:2)

  

C ++预处理器的工作原理

如果#define A B预处理器将A的所有出现替换为B。这是纯粹的替代。

  

我的项目会调用SendMessage还是SendMessageA

您的项目将调用SendMessageASendMessageW - 具体取决于是否使用unicode支持进行编译。没有SendMessage功能 - 它不存在。

  

f替换是项目不应该编译。

SendMessageA在<widnows.h>(或在windows.h中包含的标题)中声明 - 某处,其链接信息位于一个基本系统库中(我认为是User32.lib)。如果你在Windows上,那么<windows.h>很可能来自某个地方#included,并且相应的* .lib已经存在于链接器依赖项中。

- 编辑 -

  

更具体的问题:预处理器是否盲目地替换定义?

是的,预处理器盲目地替换了定义。对于非盲目替换,您有模板,但它们有自己的限制。使用预处理器可以完成的一些事情无法使用模板完成,反之亦然。预处理器具有stringize运算符,模板具有类型检查和元编程。

  

我的问题是为什么有时会调用成员函数SendMessage,因为代码有效(大部分时间)

如果您的代码中有SendMessage 方法(Windows平台上的BAD想法 - 与系统宏冲突,请替换为sendMessage()或使用其他名称,因为甚至名称空间赢了不帮助你避免无所不在的预处理器)只有{* 1}}不包含在* .cpp中时,才会从* .cpp调用你的方法(不是SendMessageA / SendMessageW)。

编译器一次只能处理一个文件,并且不知道其他文件中发生的事情,所以如果没有<windows.h> <windows.h>你的方法将会被称为,因为预处理器不会对#included SendMessage(来自#define)有任何了解。如果包含<windows.h>,那么<windows.h>的所有出现都将替换为SendMessage / SendMessageA,因为预处理器首先完成其工作。

在您的情况下,一种可能的解决方案是避免使用类似于Win API中的命名约定。即确保函数名称不以大写字母开头。这将解决许多问题,但您仍会遇到来自SendMessageW / min宏的小麻烦。

答案 3 :(得分:1)

在Windows API中,有两个函数SendMessageA和SendMessageW。您将根据程序中的#defines调用这两个中的一个。
你确定不会发生什么吗?

编辑:哦等等。在您的源中定义SendMessage成员函数之前是#define SendMessage SendMessageA吗?如果是这样,编译器将只使用SendMessageA作为成员的名称。否则,您的函数将是SendMessage,但您的程序的其余部分将调用内置的Windows函数SendMessageA。

如果您有许多源文件,可能其中一些人会知道#define,而其他人则不会。

我的建议是将成员函数重命名为其他内容并省去#define。