![]() |
|
Модераторы: feodorv, GremlinProg, xvr, Fixin |
![]()
|
|
| yngwie19 |
|
|||
|
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 829 Регистрация: 15.6.2008 Где: Новгород Репутация: нет Всего: нет |
Всем привет. У меня вопрос по функции SetWindowLong. Скажите, допустим при регистрации класса в структуре wc, конкретно в параметре wc.cbWndExtra, задаю размер 8 (байт), после этого с помощью вышеуказанной функции хочу записать 2 числа по 4 байта (т.е int). При вызове этой функции во втором параметре мы указываем смещение, т.е если мы укажем 0, то запись будет осуществляться с первого байта (т.е 1, 2,3,4 будут заняты), после чего для записи второго int мы указываем уже 4 (т.е начиная с 5-го до 8 включительно память будет занятя). Т.е когда мы указываем смещение, то имеем в виду что со следующего байта будет производится запись, так?
|
|||
|
||||
| GremlinProg |
|
|||
|
Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 2706 Регистрация: 9.8.2005 Где: Тюмень Репутация: 99 Всего: 106 |
да, так
в SetWindowLong и SetClassLong передается смещение, по которому, в памяти, ассоциируемой с окном, и хранятся пользовательские(и системные) параметры, каждый параметр имеет фиксированный размер, покрывающий двойное слово -------------------- "Гений всегда разумнее, чем умнее. Ум — это машина, разум — водитель этой машины." |
|||
|
||||
| Anikmar |
|
|||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 2513 Регистрация: 26.11.2006 Где: Санкт-Петербург Репутация: нет Всего: 59 |
А почему с 1-го, если я смещение 0 указал? |
|||
|
||||
| GremlinProg |
|
|||
|
Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 2706 Регистрация: 9.8.2005 Где: Тюмень Репутация: 99 Всего: 106 |
не понял, Anikmar, ты второй частью вопроса ответил на первую -------------------- "Гений всегда разумнее, чем умнее. Ум — это машина, разум — водитель этой машины." |
|||
|
||||
| Anikmar |
|
|||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 2513 Регистрация: 26.11.2006 Где: Санкт-Петербург Репутация: нет Всего: 59 |
Богатый русский язык. Что это? Черная смородина. А почему она красная? Потому, что зеленая! Я думал там какая-то хитрая особенность нумерации - указываешь 0, а берется байт № 1 (а не байт № 0). Вот я и уточнил: если смещение 0, то с нулевого байта нумерация или с 1-го. А так, естественно, на человеческом языке по смещению 0 находится самый что ни на есть 1-й байт. Разобрались, короче. |
|||
|
||||
| yngwie19 |
|
|||
|
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 829 Регистрация: 15.6.2008 Где: Новгород Репутация: нет Всего: нет |
||||
|
||||
| GremlinProg |
|
||||
|
Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 2706 Регистрация: 9.8.2005 Где: Тюмень Репутация: 99 Всего: 106 |
а зачем? эту память используют обычно только для хранения указателей на объекты окна ну и некоторые компоненты еще сохраняют там дополнительные флаги внутренних состояний причем в некоторых случаях есть явные ограничения на размер этой памяти:
Добавлено через 1 минуту и 50 секунд аот, Anikmar, кстати и явный пример, где без преобразования указателя к целому не обойтись -------------------- "Гений всегда разумнее, чем умнее. Ум — это машина, разум — водитель этой машины." |
||||
|
|||||
| Anikmar |
|
||||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 2513 Регистрация: 26.11.2006 Где: Санкт-Петербург Репутация: нет Всего: 59 |
Я не говорил, что нельзя преобразовывать указатель к целому вообще - это преобразование поддерживается стандартом. Я говорил об интерфейсе вызова метода - чтобы его соблюдать. Если интерфейсом предусмотрено 40 байт некой любой информации и сказано, что в эти 40 байт можно поместить что душе угодно - это не есть нарушение интерфейса. Это документированный способ передачи дополнительных параметров. Именно в таких случаях можно применить проверку (если уж совсем параноиком быть). Когда размер указателя перевалит за 40 байт думаю уже другие системы будут if (sizeof(void*) > 40) .... типа платформа для данного компилера точно не подходит. Например, может быть и такая конструкция, если приспичит - на то это и C++:
|
||||
|
|||||
| GremlinProg |
|
|||
|
Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 2706 Регистрация: 9.8.2005 Где: Тюмень Репутация: 99 Всего: 106 |
нет, это как раз именно тот случай, о котором мы с тобой и рассуждали ))
40 бай тут ни при чем, поскольку для записи их одним махом интерфейса как раз нет
в dwNewLong помещается указатель, как ни крути, и ни где не предлагается его делить порционально, значит подразумевается, что он туда именно "влезет" иначе выходит, что система не совместима с платформой, не так ли? а если так, то наш параноизм уже удовлетворила виндовс тем фактом, что приложение запущено из ее недр, инкапсулировав и решив все наши опасения я не злопамятный, просто подвернулся хороший пример, который разрешает спорную ситуацию, почему бы его не использовать -------------------- "Гений всегда разумнее, чем умнее. Ум — это машина, разум — водитель этой машины." |
|||
|
||||
| GremlinProg |
|
|||
|
Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 2706 Регистрация: 9.8.2005 Где: Тюмень Репутация: 99 Всего: 106 |
и еще один "железный" пример, чтобы отмести уже абсолютно все сомнения:
GWL_WNDPROC - смещение для указателя оконной процедуры
окно - основной компонент операционки, если GetWindowLong не возвращает корректный указатель, вследствии разноразмерности LONG и WNDPROC, то как такая система работает? -------------------- "Гений всегда разумнее, чем умнее. Ум — это машина, разум — водитель этой машины." |
|||
|
||||
| Anikmar |
|
|||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 2513 Регистрация: 26.11.2006 Где: Санкт-Петербург Репутация: нет Всего: 59 |
Согласно стандарту С++ указатель может преобразовываться в целое число, если размер целого достаточен для вмещения указателя. При обратном преобразовании указатель должен соответствовать исходному. Это по стандарту. В данном случае предполагается, что указатель влезает в dword. (Интересно, а в висте какой прототип этой функции?) Наш спор был об обратной ситуации: в прототипе требовался void*, а мы туда помещали int. И моя точка зрения была в том, что в параметрах функции надо передавать те данные, которые документированы самой функцией. Просто я не нашел в стандарте (может быть и есть), что гарантируется то, что в void* помещается int. Вот то, что в int помещается void* я где-то видел, а наоборот - не припомню, везде где смотрел говорится "платформо-зависимо". Я говорю не о том, что преобразования нельзя применять (сам применяю и достаточно часто), а о том, что в функции рекомендуется передавать параметры согласно документацию на функцию, а не общую информацию о размерах, платформах, вызовах на ассемблере и т.п. Это в общем-то даже не спор был, а отстаивание точек зрения. Я себя к параноикам не отношу, но стараюсь делать аккуратно что-ли - даже слово не подобрать. |
|||
|
||||
| GremlinProg |
|
|||
|
Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 2706 Регистрация: 9.8.2005 Где: Тюмень Репутация: 99 Всего: 106 |
я просто обобщил две функции, в предыдущем посте от GetWindowLong требуется указатель на процедуру окна, а возвращает она LONG - ситуация в точности повторяется я тоже не параноик и стараюсь следовать букве закона, если на обратное не причин два интерфейса GetWindowLong и SetWindowLong - "зеркальные" с этой точки зрения, поэтому не вижу причин для сомнений -------------------- "Гений всегда разумнее, чем умнее. Ум — это машина, разум — водитель этой машины." |
|||
|
||||
| Anikmar |
|
|||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 2513 Регистрация: 26.11.2006 Где: Санкт-Петербург Репутация: нет Всего: 59 |
Сомнений у меня нет. То что в win32 рамер указателя 4 байта понятно и ежу. То, что указатель можно передавать через целое достаточного размера прописано в стандарте и тут никакого противоречия с тем, что я говорил нет. Я не говорил, что указатель нельзя передать через целое - половина виндов на этом построена. Я говорил, что если в прототипе функции указан параметр void* не следует его использовать для передачи целого - в целях обеспечения граммотности кода и избежания возможных проблем. |
|||
|
||||
| GremlinProg |
|
|||
|
Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 2706 Регистрация: 9.8.2005 Где: Тюмень Репутация: 99 Всего: 106 |
об этом и речь, результат прототипа GetWindowLong не имеет тип void* и даже WNDPROC, он целочисленный получается, ты рекомендуешь майкрософту придерживаться стандарта, который соблюсти невозможно? поэтому целое и необходимо преобразовать к типу void*, т.е. сделать дополнительное телодвижение (void*)(long), которое заставит программиста подумать: "а не приведет ли это к сбою программы"? подумал, посмотрел на GetWindowLong и SetWindowLong и заключил - "не приведет" потом подумал, "а пойму ли я такой ход через пару дней, когда буду вновь вникать в этот код"? взвесил все за и против, и принял решение, которое от нас с тобой уже абсолютно не зависит -------------------- "Гений всегда разумнее, чем умнее. Ум — это машина, разум — водитель этой машины." |
|||
|
||||
| Anikmar |
|
|||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 2513 Регистрация: 26.11.2006 Где: Санкт-Петербург Репутация: нет Всего: 59 |
Все дело в том, что много кода написано на С, много написано старого и т.п. Эти функции виндов написаны черт знает в каком году и менять windows.h для совместимости никто естественно не будет. В качестве поддтверждения моих слов о постепенном отходе от вольных преобразований может послужить появление в стандарте таких штуковин как *_cast. Например наши обсуждаемые преобразования static_cast откажется делать. Параметр dword, который возвращает функция GetWindowLong не нарушает ни стандарта, ни моей точки зрения. Внутри функции получается каким-то образом указатель и его нужно возвратить. Как можно передать указатель через int в параметрах и это допускается стандартом, так можно его и возвратить через int в качестве возвращаемого значения - и это тоже допускается стандартом. Т.е. через int мы вернули указатель ничего особенного не нарушив, главное, что мы должны быть уверены, что указатель туда поместился. И это допускается стандартом и это документировано в описании функции. А вот если мы найдем в виндах функцию, которая возвращает void*, а в документации будет сказано, что нужно преобразовать его в int - так как через тип void* специально передано значение int, с которым потом можно работать именно как с int, то тут на лицо баг. (Может и есть такое в виндах - от них всего можно ожидать Если разработчики создали функцию, которая получает в качестве параметра некий указатель, а не целое число - возможно в этом был какой-то смысл. И при дальнейших модификациях данной функции вполне возможно, что по этому указателю будет обращение, либо проверка его на NULL и принятие на базе этой проверки решения. И если старый код вполне работал с такой функцией и в этом указателе передавался како-либо параметр, то при переносе кода в новую версию, где в этой функции этот параметр используется как указатель - то можно получить трудноуловимый баг. Я не говорю конкретно о функции CreateThread. Я говорю о подходе в целом - если есть интерфейс, он документирован и требует указателя без явных оговорок его использования - то не следует рисковать. Ну висят какие-то оголенные провода без напряжения и мы на них белье вешаем сушить. 30 лет висят, а на 31 год - возьмут на них и напряжение подадут. Провода ведь. А просто надо было сушить белье не на проводах, а на специальных веревках. |
|||
|
||||
| GremlinProg |
|
|||
|
Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 2706 Регистрация: 9.8.2005 Где: Тюмень Репутация: 99 Всего: 106 |
я вижу, ты просто не до конца понял фразы:
синее - ключевое дело не в старости кода на Си, этому языку уже много лет, и его концепции со временем только укрепляются и примеры тому - подавляющее большинство C-подобных инструментов в любой из своих промежуточных версий, майкрософт могли дополнить этот интерфейс более совместимыми аналогами, но не сделали, и это логично: если двигаться всякий раз по указателям одного и того же маршрута, то мы конечно всегда переместимся из пункта А в пункт Б, но если есть другой, более короткий путь, пусть и более грязный, но короткий, есть ли смысл его игнорировать, ведь этот путь со временем расчистят, и расставят новые указатели, потому что всем понятно, что гораздо выгоднее использовать именно его? дело в том, что соблюсти стандарт невозможно из-за того, что интерфейс Get/SetWindowLong - это узкое горлышко, через которое проходит разнородная информация чтобы следовать букве закона, в данном случае потребуется ввести массу специализаций одного метода: GetWindowLong GetWindowVoid GetWindowWndProc GetWindowModule GetWindowID GetWindowMenu и т.п., причем некоторые, на самом деле, так и реализованы, и подозреваю - только для удовлетворения общих правил но что делать с "application-defined value", в таком случае? Шаблонов в API нет до сих пор, и появиться они могут только совместно с их компоновкой в реальном времени , т.е. API должна будет поставляться совместно и со всеми инструментами разработчика, а это просто противоречит ее назначению ps: частные специализации шаблонов я не рассматриваю, при их экспорте - это конечные функции, с заведомо решенными типами данных -------------------- "Гений всегда разумнее, чем умнее. Ум — это машина, разум — водитель этой машины." |
|||
|
||||
| Anikmar |
|
||||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 2513 Регистрация: 26.11.2006 Где: Санкт-Петербург Репутация: нет Всего: 59 |
Теперь переместились ближе к виндам Мы уклонились от предмета спора. Get/SetWindowLong не нарушает стандарт С тем, что указатель передается через int32. Ограничивают совместимость, но не более - в висте будет int64. API - это отдельная тема - соглашение о вызовах системы и не более. Попытка привязать прерывания DOS к стандарту ни к чему бы не привела. WinAPI и C++ совершенно разные вещи и требовать от первой поддержки стандарта С++ глупо - это внеязыковая среда. Спор идет о стиле программирования С++, даже если это касается вызовов WinAPI. Цель разработчиков системы предоставить интерфейс для каждого языка, через который можно обращаться к системным функциям. Именно для этого и есть некая библиотека, вызывая функции которой мы обращаемся к API. Задача разработчиков этой библиотеки сделать ее таким образом, чтобы отвечала требованиям языка, к которому она относится. Соответственно появляется файл windows.h, в котром прописаны интерфейсы вызовов. Я всего лишь говорю о том, что программисту С++ не надо по большому счету знать бинарный код вызова - сколько байтов куда и для чего. Он знает хидер, в котором четко прописан прототип, а также у него есть библиотека, которая к хидеру относится. Задача программера - правильно вызвать функцию согласно прототипа. Только и всего. Вот я за это и ратую. И если в хидере написан параметр void* - то не стоит передавать int. Просто выполнять правила и все. Если требуется передать указатель, который к тому же четкого размера - то в хидере указывается dword (заметьте, не int и не long) - т.е. привязка к конкретной платформе, в которой указатель 32 бита и все тут. Жестко. Код С++ (не бинарный, а исходный, разумеется), написанный максимально вежливо - будет максимально быстро переносится на другую платформу вот и все, что я хотел собственно выразить.
Совершенно не нужно, по крайней мере для С++. Это достаточно гибкий язык. Лишнего городить не надо. Давайте подведу резюме, а то наш спор скоро всех смешить начнет. Итак, мое мнение: следует избегать нарушения в типах передаваемых параметров, особенно избегать передавать в указателе какую-либо информацию. Указатель можно передавать в целых типах согласно рекомендациям стандарта. Ваше мнение: если знаешь платформу и четкие размеры передаваемых данных, то можно передавать с преобразованиями - главное чтобы голова знала что делает. (подправьте, если это не так). Оба мнения совершенно разумны и каждый из нас естественно останется при своем. Начинающие программисты, посмотрев наш спор придут к тому или иному мнению и решат для себя лично как им действовать. |
||||
|
|||||
| GremlinProg |
|
|||
|
Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 2706 Регистрация: 9.8.2005 Где: Тюмень Репутация: 99 Всего: 106 |
ну, спорить мне тоже уже не интересно,
резюме поддерживаю, и считаю, что аргументы со своей стороны я защитил, учитывая, в каком разделе форума мы находимся -------------------- "Гений всегда разумнее, чем умнее. Ум — это машина, разум — водитель этой машины." |
|||
|
||||
| yngwie19 |
|
|||
|
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 829 Регистрация: 15.6.2008 Где: Новгород Репутация: нет Всего: нет |
Ребят Вы тут постоянно упоминиете некий "Стандарт", Я тат понимаю это про описание самого C++. Можно его на русском где-то почитать?
|
|||
|
||||
| Anikmar |
|
||||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 2513 Регистрация: 26.11.2006 Где: Санкт-Петербург Репутация: нет Всего: 59 |
Аналогично. Лучше найдем другую тему для спора.
Почему некий? Есть стандарт ANSI сейчас готовится новый. По сути - арбитр в спорах, хотя достаточно много узких мест и необнозначностей. На русском у меня нет, на английском есть, но неудобный - pdf с защитой. |
||||
|
|||||
| yngwie19 |
|
|||
|
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 829 Регистрация: 15.6.2008 Где: Новгород Репутация: нет Всего: нет |
Anikmar, а вообще на русском его в инете достать можно?
|
|||
|
||||
| Anikmar |
|
|||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 2513 Регистрация: 26.11.2006 Где: Санкт-Петербург Репутация: нет Всего: 59 |
||||
|
||||
![]()
|
| Правила форума "C/C++: Системное программирование и WinAPI" | |
|
|
На данный раздел распространяются Правила форума и Правила раздела С++:Общие вопросы . Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Chipset, Step, Fixin, GremlinProg, xvr. feodorv. |
| 0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей) | |
| 0 Пользователей: | |
| « Предыдущая тема | C/C++: Системное программирование и WinAPI | Следующая тема » |
|
|
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности Powered by Invision Power Board(R) 1.3 © 2003 IPS, Inc. |