Имеется WinAPI-функция (если быть более точным, то в данном случае это SendMessageTimeoutA), которая в качестве одного из параметров принимает аргумент типа PDWORD_PTR, который определён (по крайней мере, в моём случае — мало ли, это от каких-то макросов зависит) в заголовочном файле "basetsd.h" следующим образом:
typedef ULONG_PTR DWORD_PTR, *PDWORD_PTR;
ULONG_PTR определён как
typedef _W64 unsigned long ULONG_PTR, *PULONG_PTR;
Требуется вызвать данную функцию из кода, написанного на C++. Разумеется, все примеры в интернете пестрят вариантами с C-style кастами:
C-style касты, на мой взгляд, не должны быть в коде, написанном на C++, ведь специально для этих целей там были заведены операторы приведения типов. Впрочем, использовать reinterpret_cast тоже не очень-то и хочется, ведь существует прекрасный инструмент под названием boost::reinterpret_pointer_cast (boost в проекте итак используется, так что специально ради одного лишь каста подключать его не придётся). В таком случае каст примет вид
boost::reinterpret_pointer_cast<DWORD>(&lRes)
Обратите внимание, что в качестве шаблонного аргумента здесь используется уже не PDWORD, как это было в случае C-style каста, а DWORD. PDWORD определён как
typedef DWORD near *PDWORD;
near, по идее, это "пустой" макрос:
#define near
К чему я веду? К тому, что от изначального PDWORD_PTR мы пришли аж к DWORD*, который, казалось бы, абсолютно то же самое, но гадать, будет ли при каких-то обстоятельствах он отличаться или нет — мне не очень хочется (мало ли, какие-то макросы на это влияют или ещё что-то).
Что Вы делаете в подобных случаях? Используете C-style каст и не паритесь? Делает reinterpret_cast? Используете boost::reinterpret_pointer_cast? В общем, подскажите, пожалуйста, best practices по этому поводу.
а зачем вам вообще каст? чтобы сконвертировать LRESULT* в PDWORD_PTR? так просто используйте временную переменную с типом DWORD_PTR и потом копируйте ее куда надо.
FH>Что Вы делаете в подобных случаях? Используете C-style каст и не паритесь?
В Win API свои нравы, потому что основной интерфейс Win API (про OLE не говорю)- это С, а не С++. А поэтому там принят C-style каст. Лучше его и оставить, иначе тебя не поймут. Да и не все ли равно — там же только статические касты, то есть ничего реально не делающие, за ними не стоит код
Здравствуйте, FrozenHeart, Вы писали:
FH>Что Вы делаете в подобных случаях? Используете C-style каст и не паритесь? Делает reinterpret_cast? Используете boost::reinterpret_pointer_cast? В общем, подскажите, пожалуйста, best practices по этому поводу.
просто не смешивайте WINAPI и плюсовый код. пишите обвязки, которые уже удобно будет использовать в плюсовом коде. это стандартный подход, применяемый во взаимодействии C и C++.
внутри обвязок я использую C-style
использование boost::reinterpret_pointer_cast<DWORD> считаю неразумным, ибо усложняется восприятие кода из-за синтаксического расхождения типов аргументов (в сигнатуре функции и передаваемого аргумента). лучше в данном случае reinterpret_cast<PDWORD>, т.к. тип в сигнатуре функции и тип в касте совпадают. погружаться в обилие типов и макросов реально лениво. погрузился и забыл — вот мой подход. и коллег стараюсь не напрягать этим =)
обвязки полезны для внедрения проверок на ошибки, которые можно превращать в исключения
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>В Win API свои нравы, потому что основной интерфейс Win API (про OLE не говорю)- это С, а не С++. А поэтому там принят C-style каст. Лучше его и оставить, иначе тебя не поймут. Да и не все ли равно — там же только статические касты, то есть ничего реально не делающие, за ними не стоит код
разница есть, нельзя случайно убрать const и нарваться на #AV, или нельзя подсунуть параметр не того типа который реально ожидает функция.
type-safety вобщем.
конечно в случае каста к LPARAM и т.п. достаточно использовать c-style каст, но в других случаях лучше использовать static_cast/reinterpret_cast/numeric_cast/etc, если их использование делает код безопаснее.
Здравствуйте, Abyx, Вы писали:
A>разница есть, нельзя случайно убрать const и нарваться на #AV, или нельзя подсунуть параметр не того типа который реально ожидает функция. A>type-safety вобщем.
A>конечно в случае каста к LPARAM и т.п. достаточно использовать c-style каст, но в других случаях лучше использовать static_cast/reinterpret_cast/numeric_cast/etc, если их использование делает код безопаснее.
Можно реальный пример, где делает , для Win API, конечно ? Просто я не помню, чтобы хоть где-то в WinAPI программах использовались эти *_cast.
Здравствуйте, FrozenHeart, Вы писали:
FH>Что Вы делаете в подобных случаях? Используете C-style каст и не паритесь? Делает reinterpret_cast? Используете boost::reinterpret_pointer_cast? В общем, подскажите, пожалуйста, best practices по этому поводу.
и static_cast не спас, а только закамуфлировал проблему. ИМХО, малообоснованно надеяться, что плюсовые касты радикально изменят ситуацию лучшему при использовании WinAPI.
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>Здравствуйте, Abyx, Вы писали:
A>>разница есть, нельзя случайно убрать const и нарваться на #AV, или нельзя подсунуть параметр не того типа который реально ожидает функция. A>>type-safety вобщем.
A>>конечно в случае каста к LPARAM и т.п. достаточно использовать c-style каст, но в других случаях лучше использовать static_cast/reinterpret_cast/numeric_cast/etc, если их использование делает код безопаснее.
PD>Можно реальный пример, где делает , для Win API, конечно ? Просто я не помню, чтобы хоть где-то в WinAPI программах использовались эти *_cast.
хм... кажется я несколько поторопился осудить неиспользование *_кастов.
я тоже не могу вспомнить где имело бы смысл их использовать. это могли бы быть касты указателей LPCVOID -> T*, но я не помню API где мы получаем LPCVOID, или другой LPCXXX и должны скастовать его в какой-то другой тип
Здравствуйте, FrozenHeart, Вы писали:
FH>Что Вы делаете в подобных случаях? Используете C-style каст и не паритесь? Делает reinterpret_cast? Используете boost::reinterpret_pointer_cast? В общем, подскажите, пожалуйста, best practices по этому поводу.
Вообще это принято прятать за врапперами. Да, это излишество, но неизбежное зло на стыке двух миров. Интеграционный glue-код всегда место повышенного риска, поэтому надеяться на помощь компилятора и прочих автоматических сил — бесперспективно.
u> просто не смешивайте WINAPI и плюсовый код. пишите обвязки, которые уже удобно будет использовать в плюсовом коде. это стандартный подход, применяемый во взаимодействии C и C++. u> внутри обвязок я использую C-style
А как Вы обычно поступаете — делаете обёртки для каждой из используемых WinAPI-функций? Не слишком ли это много?
MD> Вообще это принято прятать за врапперами. Да, это излишество, но неизбежное зло на стыке двух миров. Интеграционный glue-код всегда место повышенного риска, поэтому надеяться на помощь компилятора и прочих автоматических сил — бесперспективно.
А как Вы обычно поступаете — делаете обёртки для каждой из используемых WinAPI-функций?
A> а зачем вам вообще каст? чтобы сконвертировать LRESULT* в PDWORD_PTR? так просто используйте временную переменную с типом DWORD_PTR и потом копируйте ее куда надо.
Да, здесь действительно непонятно, зачем было использовать LRESULT (код брал из примера в интернете), но это не отменяет вопроса, т.к. похожих мест при работе с WinAPI довольно много.
Здравствуйте, Abyx, Вы писали:
A>хм... кажется я несколько поторопился осудить неиспользование *_кастов. A>я тоже не могу вспомнить где имело бы смысл их использовать. это могли бы быть касты указателей LPCVOID -> T*, но я не помню API где мы получаем LPCVOID, или другой LPCXXX и должны скастовать его в какой-то другой тип
GetWindowLongPtr ?
Здравствуйте, FrozenHeart, Вы писали:
FH>А как Вы обычно поступаете — делаете обёртки для каждой из используемых WinAPI-функций?
это слишком маленькая гранулярность, ценность таких обвязок невелика
чаще всего пишутся классы \ функции, которые решают некую подзадачу
к примеру, пишется класс Thread, который внутри использует несколько WINAPI функций, для управления потоками: запуск потока, передача аргументов в функцию потока, пауза, ожидание на потоке или нескольких хендлах, освобождение ресурсов (хендлов)
класс Thread наружу выдает удобный для приложения C++ интерфейс, внутри использует несколько WINAPI функций
Здравствуйте, FrozenHeart, Вы писали:
MD>> Вообще это принято прятать за врапперами. Да, это излишество, но неизбежное зло на стыке двух миров. Интеграционный glue-код всегда место повышенного риска, поэтому надеяться на помощь компилятора и прочих автоматических сил — бесперспективно.
FH>А как Вы обычно поступаете — делаете обёртки для каждой из используемых WinAPI-функций?
Обычно это собирается в какой-то враппер-классец, который в числе прочего стимулирует клиентский код к определённому workflow. Просто оборачивать функцию другой функцией с одним лишь приведением типов — тоже можно.