реклама на сайте
подробности

 
 
> Банальный вопрос...(void*)0
promelectronshch...
сообщение Feb 16 2011, 16:33
Сообщение #1


Участник
*

Группа: Участник
Сообщений: 28
Регистрация: 8-11-10
Из: Украмна
Пользователь №: 60 714



Здравствуйте, помогите разобраться...
В многих проекта объявляется константа #define NULL (void*)0...
Зачем это делается? Мы как бы приводим тип указателя на 0 к типу void, зачем?
Go to the top of the page
 
+Quote Post
 
Start new topic
Ответов
_Pasha
сообщение Feb 17 2011, 07:29
Сообщение #2


;
******

Группа: Участник
Сообщений: 5 646
Регистрация: 1-08-07
Пользователь №: 29 509



Что мне всегда нравилось в определяющих Си стандартах - так это полное отсутствие логики. Как в данном случае - NULL это с какого-то бодуна всегда 0 и ничего более. Куда катится мир? crying.gif
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Feb 17 2011, 08:06
Сообщение #3


Гуру
******

Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095



QUOTE (_Pasha @ Feb 17 2011, 09:29) *
Что мне всегда нравилось в определяющих Си стандартах - так это полное отсутствие логики.
Если их не читать - то так и будет казаться. По определению Стандарта NULL - указатель, который не указывает ни на один объект. Не "нулевой указатель", не "указатель на ноль", а именно "указатель, который указывает в никуда". Конкретное его значение отдано на откуп компилятору.

QUOTE (Twen @ Feb 17 2011, 09:20) *
В результате я получил два идентичные результата...
Конечно. А что вы ожидали, сделав явное приведение типа x((char*)NULL)? Вы сделали явное приаведение типа - компилятор умывает руки. В языке C void * неявно приводится к указателю на любой тип и указатель на любой тип неявно приводится к void *. Поэтому в функции memcpy(), memset() и тому подобные можно передавать указатель на любые данные без явного приведения типов. И поэтому результат malloc() можно присвоить указателю на любой тип без явного приведения. Если бы вы написали x(NULL) - вы получили бы то, что ожидается.

В С++ разрешено только неявное приведение любого указателя к void *. И там добавлено неявное преобразование константы 0 к указателю на любой тип, тоже в смысле "указатель, который указывает в никуда". Какое именно значение будет занесено в указатель в результате приведения константы 0 не оговаривается. А макрос NULL в C++ изначально был введен только для совместимости исходников с С. В новом стандарте его вводят снова - с константой 0 возникают неоднозначности c перегрузкой операторов.


--------------------
На любой вопрос даю любой ответ
"Write code that is guaranteed to work, not code that doesn’t seem to break" (C++ FAQ)
Go to the top of the page
 
+Quote Post
_Pasha
сообщение Feb 17 2011, 08:13
Сообщение #4


;
******

Группа: Участник
Сообщений: 5 646
Регистрация: 1-08-07
Пользователь №: 29 509



Цитата(Сергей Борщ @ Feb 17 2011, 10:56) *
По определению Стандарта NULL - указатель, который не указывает ни на один объект. Не "нулевой указатель", не "указатель на ноль", а именно "указатель, который указывает в никуда". Конкретное его значение отдано на откуп компилятору.

Я о C99, aaarrr приводил цитату.
Да, указатель, который указывает в никуда - это единственно правильная формулировка. И если, допустим, мне в арме надо отловить обращение в никуда (как запись так и чтение), я 0 использовать не буду. Равно как и буду писАть if(ptr != NULL) вместо if(ptr)
Go to the top of the page
 
+Quote Post
Xenia
сообщение Feb 17 2011, 11:42
Сообщение #5


Гуру
******

Группа: Модератор FTP
Сообщений: 4 479
Регистрация: 20-02-08
Из: Москва
Пользователь №: 35 237



Цитата(_Pasha @ Feb 17 2011, 11:13) *
Да, указатель, который указывает в никуда - это единственно правильная формулировка. И если, допустим, мне в арме надо отловить обращение в никуда (как запись так и чтение), я 0 использовать не буду. Равно как и буду писАть if(ptr != NULL) вместо if(ptr)

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

Если же все мы согласны с тем, что типы указателей компилятор должен проверять (например, не допуская подстановки указателя на char вместо указателя на int), то должны понимать и то, что подстановка числа вместо указателя - гораздо бОльшая вольность, чем подмена указателей на разные типы данных. Уже только потому, что указатели разных типов - это все-таки адреса областей памяти, а числа - совершенно другая ипостась. Подразумевается, что по умолчанию программист не знает точных адресов, где будут располагаться программные объекты (исключения встречаются, но общая стратегия этого требует), а потому число, введенное вместо адреса, - обычно ошибка подсчета порядкового номера аргумента в параметрах функции, когда они по недосмотру "сползают". А если уж программист делает такое потенциально опасное действие, как подстановка числового адреса, то не будет бедой, если он оформит свое желание явным переопределением типа.

Если разрешено подставлять вместо указателя 0, то почему нельзя 5, или 176, или любое алгебраическое выражение? Надо понимать, что, идя по пути легализации нуля, как допустимого указателя, мы ступаем на очень шаткий мостик. Нет разумных доводов в пользу того, что число 176 можно поставить в качестве указателя, а элемент массива M[i] нельзя, поскольку то и другое - числа. Но стоит только разрешить M[i] в качестве указателя, то начнет возникать путаница между M[i] и &M[i], аналогичная тому, как случается такая путаница между именами и указателями на строковые массивы (многие долбят перед его именем &, когда само имя - уже указатель).

По этим причинам, допущение подстановки нуля вместо указателя - не самая лучшая идея. И здесь специальный объект NULL - хороший выход из этого положения, т.к. его введение не нарушает строгости контроля типов и повышает дисциплину программирования. Ведь не даром же наиболее жесткая критика языка С/С++ раздается из-за разрешенных операций с указателями, позволяющими писать в произвольное место памяти. Это много серьезнее, чем безобидный goto sm.gif.

Однако и в этом случае использовать выражение if(ptr) вполне допустимо, т.к. здесь указатель приводится к логическому типу, а не наоборот. Такое приведение типов по своей природе безвредно. Как, впрочем, и превращение указателя в число. А вот превращение числа в указатель - крайне опасная вещь. Ведь запись по случайному указателю может разрушить структуру памяти всего приложения, а то и операционной системы. Тогда как неправильное число в переменной - не так уж и страшно.
Go to the top of the page
 
+Quote Post



Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 28th July 2025 - 14:41
Рейтинг@Mail.ru


Страница сгенерированна за 0.01411 секунд с 7
ELECTRONIX ©2004-2016