我有一个名为SendMessage
的成员函数的类。项目中不存在名为SendMessageA的成员函数。
项目是多字节的,所以我有一个定义
#define SendMessage SendMessageA
如果我在该课程的某个地方致电SendMessage
,我的项目会调用SendMessage
还是SendMessageA
?
如果替换是由预处理器完成的,则项目不应编译。对吗?
但我在转储中看到SendMessageA
被调用...结束eip寄存器不在任何VAD中
修改
更具体的问题:预处理器是否盲目地替换了定义?或首先检查班级中的匹配?
答案 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
?
您的项目将调用SendMessageA
或SendMessageW
- 具体取决于是否使用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调用这两个中的一个。
你确定不会发生什么吗?
#define SendMessage SendMessageA
吗?如果是这样,编译器将只使用SendMessageA作为成员的名称。否则,您的函数将是SendMessage,但您的程序的其余部分将调用内置的Windows函数SendMessageA。
如果您有许多源文件,可能其中一些人会知道#define,而其他人则不会。
我的建议是将成员函数重命名为其他内容并省去#define。