Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате |
Форум программистов > C/C++: Общие вопросы > Проверка указателей на валидность |
Автор: Sergio 5.11.2007, 16:31 |
Здраствуйте. Как проверить указатель на валидность? Проверять на NULL или еще есть способы? Заранее спасибо. |
Автор: MAKCim 5.11.2007, 16:47 |
Sergio, все зависит от того, какие в твоем случае критерии валидного указателя в общем случае проверить валидность средствами языка нельзя должна быть поддержка со стороны API ОС однако если указатель нулевой, то с большой вероятностью он не валиден |
Автор: Sergio 5.11.2007, 17:37 |
А переменные типа int лучше инициализировать 0 или NULL? |
Автор: MAKCim 5.11.2007, 18:48 | ||
Alexeis, при чем здесь 32-ух разрядные регистры? они вполне могут хранить адрес, не кратный степени двойки
как одно связано с другим? нулевой разряд регистра не может быть единичным? |
Автор: Alek86 5.11.2007, 19:11 |
_CrtIsValidPointer посмотри |
Автор: Alexeis 5.11.2007, 20:51 |
MAKCim, представь что предыдущая структура имела нечетную длину, например заканчивается байтом. За ней начинается новая структура. Если прочитать этот байт как DWORD, то автоматом захватим еще кусок соседней структуры. Если мы можем использовать четвертинку регистра, то это нам позволит прочитать только 1 байт и получить верное значение в регистре, а если нет, то единственная возможность прочитать правильное значение, это производить несколько битовых операций. Компилятор сразу отбрасывает использование битовых операций, как неэффективное средство доступа к памяти, потому все структуры и объекты выравниваются на границу 4х байт. Если объявляется сначала переменная в байт, а затем скажем DWORD, то вместо байта компилятор выделит тоже DWORD, т.о. почти всегда адреса получается четными. Для процессоров i486 совместимых обычно делается тоже самое, но в целях оптимизации по скорости. MAKCim, можешь глянуть под дебагом адреса и проверить. |
Автор: archimed7592 5.11.2007, 20:51 |
В общем случае - никак. Давай конкретные примеры. Учти, что, если появилась необходимость проверять не нулевой указатель на валидность, то это, с огромной вероятностью, ошибка проектирования. |
Автор: Alexeis 5.11.2007, 20:53 | ||
|
Автор: Alek86 5.11.2007, 21:17 |
что вспомнил, то и ляпнул ![]() тогда только умные ресурсы, которые при удалении обнуляют указатели. или всеми любимый boost::shared_ptr (хотя все еще не знаю, насколько он тормозит программу ![]() |
Автор: MAKCim 5.11.2007, 21:36 | ||||||||
битовые операции и доступ к памяти никак не связаны
кроме того, выравнивание спасает от мусора только глобальные объекты т. е в случае массива, мы действительно не затроним следующий объект но используя стек, в любом случае будет мусор, читаем ли мы однобайтовое поле как 4-х байтовое или 4-х байтовое как 4-х байтовое |
Автор: Lazin 5.11.2007, 22:21 |
Есть еще такие функции IsBadWritePtr IsBadReadPtr, _CrtIsValidPointer видимо на их основе построена |
Автор: Alexeis 5.11.2007, 23:54 |
MAKCim, а как тогда объяснить причину ошибки "Data Type Misalignment", которая возникает при попытке обратиться по нечетному адресу и при включении директивы pragma pack(0) Значит так оптимальнее или еще по чему. Мож гляуть в хелп. Добавлено через 6 минут и 3 секунды Я имел ввиду, что для того чтобы считать значение нужно производить битовую операцию. Это дольше чем просто обратиться! С массивами я же говорил все ок. Видимо так он и делает. Для элементов массивов можно использовать нечетные. |
Автор: DominiK 6.11.2007, 00:24 | ||
Разницы нету. |
Автор: archimed7592 6.11.2007, 08:41 |
Зависит от того Си это или Си++. |
Автор: MAKCim 6.11.2007, 10:10 | ||||
установка AM в CR0 и AC в EFLAGS включает генерацию #AC (Alignment Check) в случае обращения по невыровненным адресам но это никак не связано с оптимизацией обработка исключительной ситуации на уровне процессора куда менее эффективное средство для достижения оптимального результата
здесь массив не причем смысл инструкции - прочитать байт в регистр, размер которого превышает 8 разрядов (с нулевым расширением до полного размера) это к вопросу о дополнительных манипуляциях |
Автор: Alexeis 6.11.2007, 10:34 | ||
Почему? Разве эффективнее делать 10 проверок чем одну обработку исключения? |
Автор: MAKCim 6.11.2007, 10:57 | ||
хорошо а как ты отличишь обращение к элементу массива от, например, обращения к полю структуры? каждый раз компилятор вынужден будет встявлять куски кода по установке и сбросу AC это более эффективно? |
Автор: Alexeis 6.11.2007, 11:21 | ||
MAKCim, ну мой текущий компилятор это как-то делает, хотя у меня создается впечатление, что для массивов он использует другую схему обращения при этом избегает нечетных адресов.
Думаю он использует для этого разные команды. По крайней мере с вероятностью 50/50 можно определить, то что указатель невалидный. Чем раньше об этом узнаешь тем ближе окажешься к источнику ошибки. Так что положительный момент в этом есть. Вот только я не уверен, можно ли организовать такую же схему для i486. |
Автор: archimed7592 6.11.2007, 11:37 |
Дельфи? IIRC, он программно полностью контролирует доступ к памяти(в дебаге). |
Автор: Alexeis 6.11.2007, 11:45 |
archimed7592, я сейчас говорю про eVC. Добавлено @ 11:46 Мы же в разделе С++. С чего бы тут обсуждать компилятор Делфи... [оффтоп]У делфей такие проблемы возникают намного реже, так как там строки/массивы/интерфейсы это управляемая память. Зря напомнили ![]() |
Автор: MAKCim 6.11.2007, 11:51 | ||
![]() не в команде дело если у нее есть адресный операнд, то в любом случае существует возможность исключения если чтение/запись массива выполняется по выровненным адресам, то тогда требуются дополнительные телодвижения для того, чтобы прочитать/записать данные а ты вроде сам писал
где оптимизация? ![]() |
Автор: Alexeis 6.11.2007, 11:57 |
MAKCim ну с асмом мне работать не приходиться, тем более с его различными спецификами, потому даж не знаю как. Читал, что выравнивание делается в целях оптимизации. А как тут без понятия. Если хош могу показать кусок асма. Ща попробую. |
Автор: MAKCim 6.11.2007, 12:01 |
давай |
Автор: archimed7592 6.11.2007, 12:26 |
Не только, особенно, если речь про eVC - многие архитектуры не поддерживают обращение по невыровненому адресу. |
Автор: Alexeis 6.11.2007, 12:29 | ||
|
Автор: MAKCim 6.11.2007, 12:48 | ||
Alexeis,
неизвестно, какое значение в r0 после bl поэтому неизвестно, какой адрес получается в этом месте (r0 + 1) и в этом в не зависимости от базового адреса массива x из двух адресов x + 1 и x + 2 по определению как минимум один из них - не кратен 4-м Добавлено @ 12:49 Alexeis, ассемблер похож на MIPS оно? |
Автор: pompei 6.11.2007, 13:56 | ||
Как видишь проверка указателя на валидность очень сложная задача. А раз так то постарайтся поступить по простому, постарайся избежать её. Например с помощью такого метода: прими что = 0 (NULL) - это инвалидный указатель, остальные валидные. Тогда получается необходимо всегда писать так:
|
Автор: Lazin 6.11.2007, 14:23 | ||
это неверно, если указатель не равен 0, это не значит что он валидный, указатель может указывать неизвестно куда, например в адресное пространство другого процесса. Я уже писал, что есть функции для проверки, указывает ли указатель на область памяти в куче или хрен знает куда (IsBadWritePtr IsBadReadPtr, итд, смотри MSDN). Но даже если он указывает на объект в куче, это еще не значит что он правильный, так как может указывать на уже удаленный объект. Обычно указатели инициализируют 0, и после удаления объекта обнуляют указатель, чтобы по значению указателя можно было узнать указывает ли он на объект или нет. |
Автор: MAKCim 6.11.2007, 14:58 | ||
есть решение под Linux (но немного извращенное)
|
Автор: Alexeis 6.11.2007, 17:04 | ||
Я тоже так подумал. Да и дебагере можно прочитать с нечетного адреса прибавив к указателю на байт единицу и разъыменовав. При это все ок. Выходит, что проверка включается при обращении к структурам/массивам. p.s. я пропадаю на пару дней. Приеду гляну как происходит обращение к структуре. Я не знаю что такое MIPS. |