Препроцессор слепо заменяет определения? - PullRequest
0 голосов
/ 09 декабря 2011

У меня есть класс, который имеет функцию-член под названием SendMessage.В проекте не существует функции-члена с именем SendMessageA.Проект многобитный, поэтому у меня есть определение

#define SendMessage SendMessageA

Если я позвоню SendMessage где-нибудь в этом классе, мой проект вызовет SendMessage или SendMessageA?

Если замена сделана препроцессором, проект не должен компилироваться.Правильно?
Но я вижу в дампе, что SendMessageA называется ... end eip register не находится ни в одном VAD

EDIT

Более конкретновопрос: препроцессор слепо заменяет определения?или первые проверки на совпадение в классе?

Ответы [ 4 ]

3 голосов
/ 09 декабря 2011

Препроцессор просматривает ваш код перед компиляцией. Таким образом, любое SendMessage будет преобразовано в SendMessageA. Затем компилятор будет искать функцию с именем SendMessageA и вызывать ее.

2 голосов
/ 09 декабря 2011

Как работает препроцессор 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 уже находится в зависимостях компоновщика.

- EDIT -

Более конкретный вопрос: препроцессор вслепую заменяет определения?

Да, препроцессор вслепую заменяет определения.Для не слепой замены у вас есть шаблоны, но у них есть свои ограничения.Что-то, что можно сделать с помощью препроцессора, нельзя сделать с помощью шаблонов и наоборот.В препроцессоре есть оператор stringize, в шаблонах есть проверка типов и метапрограммирование.

Моя проблема в том, почему иногда вызывается функция-член SendMessage, потому что код работает (большую часть времени)

Если у вас есть SendMessage метод в вашем коде (идея ПЛОХО на платформе Windows - конфликтует с системным макросом, замените на sendMessage() или используйте другое имя, потому что даже пространства имен не помогут вам избежать вездесущего препроцессора) ваш метод (не SendMessageA / SendMessageW) будет вызываться ТОЛЬКО из * .cpp, если <windows.h> не было включено в этот * .cpp.

Компилятор работает с одним файлом за раз и не знает, что происходит в других файлах, поэтому, если нет <windows.h> #included, , будет вызван ваш метод потому что препроцессор не будет знать о SendMessage #define (из <windows.h>).Если включено <windows.h>, то ВСЕ вхождения SendMessage будут заменены на SendMessageA / SendMessageW, потому что препроцессор сначала выполняет свою работу.

Одним из возможных решений в вашей ситуации было бы избегать использования соглашения об именовании, аналогичного соглашению в Win API.Т.е. убедитесь, что имена функций не начинаются с заглавной буквы.Это решит многие проблемы, но вы все равно получите небольшие проблемы с min / max макросами.

2 голосов
/ 09 декабря 2011

Препроцессор работает как текстовый макропроцессор. Если макрос определен, все вхождения макроса заменяются его определением.

#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();
}
1 голос
/ 09 декабря 2011

В Windows API есть две функции SendMessageA и SendMessageW. Вы будете звонить одному из этих двух, в зависимости от того, какие #defines есть в вашей программе.
Вы уверены, что это не то, что происходит?

Редактировать: ой, подождите. Ваш #define SendMessage SendMessageA до определения функции-члена SendMessage в вашем источнике? Если это так, компилятор просто использует SendMessageA для имени члена. В противном случае ваша функция будет SendMessage, но остальная часть вашей программы вызовет встроенную в Windows функцию SendMessageA.

Если у вас много исходных файлов, возможно, некоторые из них будут знать о #define, а другие нет.

Я рекомендую переименовать функцию-член во что-то другое и обойтись без # define.

...