![]() |
Модераторы: bsa |
![]() ![]() ![]() |
|
Merlin_ua |
|
||||
Новичок Профиль Группа: Участник Сообщений: 44 Регистрация: 22.11.2006 Репутация: нет Всего: нет |
Насколько мне извесно в C NULL - это указатель на нулевой адрес, поэтому и определен ((void *)0) и не в коем случае нулевой значение какого-то объекта. В плюсах NULL оставили из-за совместимости, и не рекомендуют им пользоваться, а вместо него писать 0. Или же самому на свой страх и риск определить NULL и следить за его использованием. а то что
так здесь нужно смотреть на объявление функции, и компилятор должен по правилам приведения привести NULL к нужному типу, так что каких-то глюков с стеке быть не должно!!! По поводу нулевого указателя, так это скорее всего больше условность, обусловленная средой выполнения. Думаю в низкоуровневом программировании есть возможность использования адреса 0х00000000. Насчет
правильно выразиться для каждого процесса свой нулевой адрес. Опять таки, зависит от среды выполнения. Процесс может работать как в виртуальном адресном пространстве с контролем доступа, здесь у каждого процесса свое виртуальное адресное пространство так и в реальном адресном пространстве(системные процесс например) - здесь один нулевой адрес, и 0-1 = последний адрес а адресном пространстве цпу. Вообще, вся работа с памятью будет зависить от среды выполнения. Для высокоуровневого программирования указатель на 0 - это неинициализированный указатель, его использование вызовет ошибку. Также рекомендуется поменьше арифметики с адресами, так как после некоторых опяраций поведение программы непредсказуемы, например 0-1 может вызвать исключение, и если его не обработать - то крах процесса. |
||||
|
|||||
feodorv |
|
|||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 2214 Регистрация: 30.7.2011 Репутация: 12 Всего: 45 |
Это значит действие, приводящее к нарушению целостности кучи. Например, нечаянная запись в область структур кучи. В виндах даже можно проверить валидность кучи - HeapValidate Нарушить целостность кучи возможно, но специально прямо щас я это сделать не смогу. Просто в некоторых случаях HeapAlloc возвращает NULL, если куча разрушена, хотя свободная память в необходимом объеме все же есть. Тогда указатель ptr будет указывать на байт под номером один в адресном пространстве процесса.
К тому, чтобы указатель указывал на первый байт процесса, упомянутая защита никакого отношения не имеет. Вот если Вы возьметесь за разименовывание этого указателя (*ptr), тогда защита сработает. Уф. Изначально процессу передаются не все страницы памяти. Вернее, не только лишь все, мало какие. А в нашем случае оговариваемые страницы резервируются, но не передаются процессу. ЗЫ В C/C++ принято все отсчитывать от нуля. И очень сложно в Ваших вопросах адекватно воспринимать фразы типа "первый байт", "первая страница". -------------------- Напильник, велосипед, грабли и костыли - основные инструменты программиста... |
|||
|
||||
feodorv |
|
||||||||||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 2214 Регистрация: 30.7.2011 Репутация: 12 Всего: 45 |
Объявление функции (кстати, я его уже приводил):
Пожалуйста, из указанного объявления функции приведите аргумент 0 (а не упоминаемый Вами NULL) к нужному виду:
Это не условность. Значение 0 выбрано из соображений быстрой работы с регистрами процессора. Загружать какое-то ненулевое значение в регистры процессора дольше (и требует больше исполняемых кодов), чем просто ноль. Ноль так же подходит и по неким философским соображениям, на основании которых создавался язык C.
Использовать - в каком смысле. Но учтите, что современные пользовательские процессы все равно закрывают область вокруг нулевого байта на чтение/запись, все равно, с языка высокого уровня был скомпилирован процесс, или набит прямо в кодах.
Это как раз инициализированный указатель, инициализированный значением 0. Кстати, где Вы учились? Его разыменовывание вызовет ошибку. А использовать я его могу:
Давайте разберёмся с пользовательскими, пожалуйста. Пример, когда запись по адресу NULL прошла в пользовательском процессе, я уже описывал. -------------------- Напильник, велосипед, грабли и костыли - основные инструменты программиста... |
||||||||||
|
|||||||||||
Merlin_ua |
|
||||||||||||
Новичок Профиль Группа: Участник Сообщений: 44 Регистрация: 22.11.2006 Репутация: нет Всего: нет |
Понял. В данном случае у Вас функция с переменным/незвестным колличеством и типом аргументов. В таких случаях вся ответственность на то, что попадает в стек и как его оттуда извлекать на программисте. А насчет
так 0 по умолчанию это int На платформе IA32 с компилятором от Microsoft или GCC в стек пойдет 4 байта.
Вы наверное имели ввду обнуление регистров а не загрузку. Загружать в регистр по времени что 0х00000000 что 0xffffffff одинаково, а вот обнулить регистр путем вычитания самого себя - быстрее чем загрузка 0х00000000. Насчет соображений и философии тоже с Вами согласен.
Не пользовательские процессы, а среда выполнения Runtime Environment, и Вы правы, всеравно на чем набит код. Среда ограничит действия кода. И будет закрыта не только область вокруг нулевого байта. Там много к чему еще будет ограничен доступ.
Ошибся. Неправильно выразил мысль. Я хотел сказать, доступ к памяти, на которую ссылается нулевой указатель вызовет ошибку. А что Вы так о моем образовании? Если у меня нет образования то что Вы хотите сказать? Что у мне нет места здесь? Или я не имею права поучаствовать в теме? Тема ж для новичков! Я не претендую на звание высоквалифицированного программиста. Я - не волшебник, я только учусь! Ну а Вы, если имеете солидную квалификацию, поправте где я не прав, научите как правильно!
Так я и не против! И про запись по NULL в пользовательском процессе тоже не спорю. Я лишь хотел хотел выразить мысль, что там, где идет работа с памятью и необходимо понимание протекающих с нею манипуляций нужно учитывать runtime environment. |
||||||||||||
|
|||||||||||||
feodorv |
|
||||||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 2214 Регистрация: 30.7.2011 Репутация: 12 Всего: 45 |
Конечно)))
Так, навеяло))) Извините, если что... -------------------- Напильник, велосипед, грабли и костыли - основные инструменты программиста... |
||||||
|
|||||||
Merlin_ua |
|
|||
Новичок Профиль Группа: Участник Сообщений: 44 Регистрация: 22.11.2006 Репутация: нет Всего: нет |
А что там в эпоху 16-разрядных систем? Если нетрудно - расскажите. Я в эти времена еще в школе учился на турбо-паскале на Поиске 2! Неужели стандарты тех времен не имели 0 по умолчанию? И что странного "(void *) 0"? Хотя что-то тут есть неудобовразумительное. В некоторых технологиях оговаривают, что NULL - это не 0, и использовать вместо NULL - 0 запрещают (по моему встречал такую оговорку в COM). В плюсах рекомендуют не использовать NULL или определить по собственному усмотрению.
|
|||
|
||||
feodorv |
|
||||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 2214 Регистрация: 30.7.2011 Репутация: 12 Всего: 45 |
Гм. А Вы вопрос ТС читали? А последующие соображения? А Вы в плюсах такой код пробовали:
???
Потому что в код C++ может быть включен заголовок, где NULL определен как "(void *) 0". Со всеми вытикающими... nullptr призван спасти ситуацию. Это сообщение отредактировал(а) feodorv - 30.8.2014, 13:30 -------------------- Напильник, велосипед, грабли и костыли - основные инструменты программиста... |
||||
|
|||||
Merlin_ua |
|
||||||||||
Новичок Профиль Группа: Участник Сообщений: 44 Регистрация: 22.11.2006 Репутация: нет Всего: нет |
Читал. Вы наверно имеете ввиду следующие соображения:
Здесь хочу отметить следующее: 1. В случае с void func( ... ) контроль за аргументами функции полностью возлагается на программиста, и то, что у Вас там может не докладывается 2 нужных нулевых байта или же окажется какой-то мусор - это полностью ответственность программиста. 2.Я подозреваю, в настоящей теме, под 16-битной системой подразумевается Intel8086. Так вот. здесь не стоит путать физический и эффективный адрес. Указатели используют 16-разрядный эффективный адрес. Так что и sizeof(int) и sizeof(int*) имеют 2 байта. Манипуляции с 16-разрядным адресным регистром и сегментным регистром происходят на нижних уровнях - на системном уровне ОС.
В плюсах контроль над типами другой.
Полностью согласен. О NULL в плюсах даны конкретные рекомендации! |
||||||||||
|
|||||||||||
feodorv |
|
||||||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 2214 Регистрация: 30.7.2011 Репутация: 12 Всего: 45 |
Да, поэтому программист и пишет:
Совсем не обязательно (по ссылке перечислено множество 16-битных процессоров). 16-битные процессоры разрабатываются до сих пор. Ну пусть будет Intel8086/Intel80286. Да ладно))) Far-указатели используют как базу, так и индекс. Каждая величина является 16-битным значением. В сумме - 32 бита при 16-битном выравнивании. См. модели памяти. Чувствуется, что Вы никогда не программировали на 16 битах на far-указателях. Модель данных, при которой int занимает 2 байта, а указатель - 4 байта, называется I16LP32, и применялась она не только на Интелах. Это сообщение отредактировал(а) feodorv - 31.8.2014, 01:22 -------------------- Напильник, велосипед, грабли и костыли - основные инструменты программиста... |
||||||
|
|||||||
Merlin_ua |
|
||||
Новичок Профиль Группа: Участник Сообщений: 44 Регистрация: 22.11.2006 Репутация: нет Всего: нет |
Да, вы полностью правы! far указатели не использовал! Спасибо, что объяснили!
Почему не верный? в первом случае Вы передаете ((void *)0) во втором int. Ведь void func( ... ) говорит о том, типы и их количество не известны! |
||||
|
|||||
feodorv |
|
||||||||||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 2214 Регистрация: 30.7.2011 Репутация: 12 Всего: 45 |
Потому что func ожидает указатель. А не интегер. NULL служит указанием того, что список аргументов (указателей на строки) завершен. Такое было в моде одно время.
Именно. Значит func как-то должна знать, что ей передают. printf, например, использует форматную не только для того, чтобы оформить вывод, но и для того, чтобы понять типы переданных ей аргументов. Но даже здесь NULL может быть полезен (пример весьма искусственен, ну да ладно):
Последняя строка должна выглядеть так:
В случае func с переданным ей неопределённым числом указателей на строки как-то нужно сообщить функции число этих самых указателей. Это можно было бы сделать так:
не заботясь о числе аргументов, но завершая их список нулевым указателем. Когда func, выбирая указатели на строки из списка аргументов, натыкается на NULL, она понимает, что всё, список аргументов исчерпан. Когда она натыкается на 0 и ещё два каких-то случайных (скорее всего ненулевых) байта, то она продолжит обработку списка аргументов... -------------------- Напильник, велосипед, грабли и костыли - основные инструменты программиста... |
||||||||||
|
|||||||||||
Merlin_ua |
|
||||||||||||||
Новичок Профиль Группа: Участник Сообщений: 44 Регистрация: 22.11.2006 Репутация: нет Всего: нет |
Я понял Вашу мысль. Но я также хочу что б Вы поняли и мою. Давайте вернемся к началу.
и здесь пояснение
Я так понимаю, что аргументы будут выбираться до тех пор, пока не встретится последовательность из 4-х байт равных 0х00. Тогда в случае
или же
Вы не только потеряете аргументы, но и приведете к краху программы. Я хочу донести мысль, что крах в случае с использованием void func( ... ) не из-за того, что int может быть двухбайтовым а NULL четырехбайтовым. И мысль
мне тоже не понятна. Хотя возможно это и так. |
||||||||||||||
|
|||||||||||||||
feodorv |
|
||||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 2214 Регистрация: 30.7.2011 Репутация: 12 Всего: 45 |
И не донесете. Крах в случае намеренно некорректного программирования неизбежен. Иное дело, когда все запрограммировано на вид правильно, а оно рушится. Был поставленный ТС вопрос: зачем (void *) 0, а не просто 0. Прозвучал ответ: Все остальное - лишь иллюстрация к этому утверждению. В том числе и с двухбайтовым int и четырёх байтовым указателем при двубайтовом выравнивании (а именно это и стало исторической реальностью). Ровно такая же ситуация была бы и при однобайтовом int, двубайтовом указателе и однобайтовом выравнивании. Ровно такая же ситуация была бы и при четырех байтовом int, восьмибайтовом указателе и четырехбайтовом выравнивании. Поэтому для программиста важно определение NULL как (void *) 0, а не просто как 0. И ни по какой другой причине. В качестве примера взята функция func(...) которая работает с набором указателей на строки. Причем здесь a, b, c - это указатели на строки? ![]() Честно, мне лень лазить по интернету, чтобы подкрепить свои слова чужими. Вот на вскидку:
-------------------- Напильник, велосипед, грабли и костыли - основные инструменты программиста... |
||||
|
|||||
Merlin_ua |
|
||||||||||||||||
Новичок Профиль Группа: Участник Сообщений: 44 Регистрация: 22.11.2006 Репутация: нет Всего: нет |
По всей видимости да!
Определено стандартом или Ваше личное суждение?
Где оговорено, что в качестве аргументов исключительно указатели на строки??? Вы действительно не понимаете что такое a, b, c или притворяетесь ??? И если Вам не понятен мой пример, так это тоже лишь иллюстрация.
Будет! Также, как и в Вашем случае, когда Вы не докладываете два байта с стек
так как в стеке остается куча мусора.
Это похоже из той серии, где шла речь об образовании.
Это что? ответ на
или доказательство ликвидности Ваших примеров??? Выше я писал, что ликвидность лишь в частных случаях!! |
||||||||||||||||
|
|||||||||||||||||
feodorv |
|
||||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 2214 Регистрация: 30.7.2011 Репутация: 12 Всего: 45 |
Определено что?
То есть я обязан все разжевывать? Из примера не ясно? Ну извините.
Как краха программы не будет, так и потери аргументов. Это доказательство того, что не просто ![]() -------------------- Напильник, велосипед, грабли и костыли - основные инструменты программиста... |
||||
|
|||||
![]() ![]() ![]() |
Правила форума "C/C++: Для новичков" | |
|
Запрещается! 1. Публиковать ссылки на вскрытые компоненты 2. Обсуждать взлом компонентов и делиться вскрытыми компонентами
Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, JackYF, bsa. |
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей) | |
0 Пользователей: | |
« Предыдущая тема | C/C++: Для новичков | Следующая тема » |
|
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности Powered by Invision Power Board(R) 1.3 © 2003 IPS, Inc. |