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

 
 
> Банальный вопрос...(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
Ответов (1 - 10)
Xenia
сообщение Feb 16 2011, 16:58
Сообщение #2


Гуру
******

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



Цитата(promelectronshchic @ Feb 16 2011, 19:33) *
Здравствуйте, помогите разобраться...
В многих проекта объявляется константа #define NULL (void*)0...
Зачем это делается? Мы как бы приводим тип указателя на 0 к типу void, зачем?

Чтобы такой нулевой указатель компилятор принимал в качестве аргумента функций и не ругался на него.

Нулевой указатель частенько применяется в аргументах функций, когда данный параметр опускается (в смысле не нужен). Типа пустая затычка sm.gif. А для некоторых функций такой параметр может означать, что вместо нулевого адреса они могут взять адрес по умолчанию или из каких-то разумных соображений. Типа того, что если укажешь адрес буфера, то тебе в него что-то насыплют, а если не укажешь, но ничего не насыпют sm.gif. В последнем случае NULL работает как признак затребования опционных данных, которые отпускаются, когда под них приготовлена ёмкость. NULL - отсутствие такой ёмкости, отказ от опционных данных.

Хотя сейчас появилось довольно много С++ компиляторов, которые способны обычный 0 (цифру) автоматичеcки приводить к типу void*. Тогда определение NULL становится ненужным. А точнее, нужным только в чистом языке C. Хотя все-таки приятнее уметь отличать на глаз цифру 0 от нулевого указателя.
Go to the top of the page
 
+Quote Post
aaarrr
сообщение Feb 16 2011, 18:20
Сообщение #3


Гуру
******

Группа: Свой
Сообщений: 10 713
Регистрация: 11-12-04
Пользователь №: 1 448



Цитата(Xenia @ Feb 16 2011, 19:58) *
Хотя сейчас появилось довольно много С++ компиляторов, которые способны обычный 0 (цифру) автоматичеcки приводить к типу void*. Тогда определение NULL становится ненужным. А точнее, нужным только в чистом языке C. Хотя все-таки приятнее уметь отличать на глаз цифру 0 от нулевого указателя.

Из стандарта C99:
Цитата
6.3.2.3 Pointers
...
3 An integer constant expression with the value 0, or such an expression cast to type
void *, is called a null pointer constant.55) If a null pointer constant is converted to a
pointer type, the resulting pointer, called a null pointer, is guaranteed to compare unequal
to a pointer to any object or function.
...
55) The macro NULL is defined in <stddef.h> (and other headers) as a null pointer constant; see 7.17.
Go to the top of the page
 
+Quote Post
sergeeff
сообщение Feb 16 2011, 18:28
Сообщение #4


Профессионал
*****

Группа: Свой
Сообщений: 1 481
Регистрация: 10-04-05
Пользователь №: 4 007



Код
/* Define NULL pointer value */
#ifndef NULL
#ifdef __cplusplus
#define NULL    0
#else
#define NULL    ((void *)0)
#endif
#endif

Go to the top of the page
 
+Quote Post
aaarrr
сообщение Feb 16 2011, 18:29
Сообщение #5


Гуру
******

Группа: Свой
Сообщений: 10 713
Регистрация: 11-12-04
Пользователь №: 1 448



Цитата(promelectronshchic @ Feb 16 2011, 19:33) *
Зачем это делается? Мы как бы приводим тип указателя на 0 к типу void, зачем?

Например, чтобы компилятор ругнулся, если NULL используется инициализации переменной, не являющейся указателем, типа "int e = NULL;".
Go to the top of the page
 
+Quote Post
andrew_b
сообщение Feb 17 2011, 05:37
Сообщение #6


Профессионал
*****

Группа: Свой
Сообщений: 1 975
Регистрация: 30-12-04
Из: Воронеж
Пользователь №: 1 757



Цитата(Xenia @ Feb 16 2011, 19:58) *
Хотя сейчас появилось довольно много С++ компиляторов, которые способны обычный 0 (цифру) автоматичеcки приводить к типу void*.
Гм, а раньше что, нельзя было? Вы читали Страуструпа? Он рекомендует использовать именно 0 вместо NULL.
Go to the top of the page
 
+Quote Post
Twen
сообщение Feb 17 2011, 07:20
Сообщение #7


Частый гость
**

Группа: Участник
Сообщений: 163
Регистрация: 7-02-09
Пользователь №: 44 543



Цитата
Нулевой указатель частенько применяется в аргументах функций, когда данный параметр опускается (в смысле не нужен).


Не совсем понятно выражение - нулевой указатель, правильнее сказать указатель типа void, который указывает на ячейку памяти с нулевым адресом, правильно?

Я правильно понял, это делается для того, чтобы передать в качестве параметра функции нулевой адрес:

#define NULL ((void*)0)

void x(char *y)
{
if(y==0)...
else...
}

void main(void)
{
x((char*)NULL);
}


Или второй вариант:
#define NULL 0

void x(char *y)
{
if(y==0)...
else...
}

void main(void)
{
x((char*)NULL);
}

В результате я получил два идентичные результата...
Go to the top of the page
 
+Quote Post
_Pasha
сообщение Feb 17 2011, 07:29
Сообщение #8


;
******

Группа: Участник
Сообщений: 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
Сообщение #9


Гуру
******

Группа: Модераторы
Сообщений: 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
Сообщение #10


;
******

Группа: Участник
Сообщений: 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
Сообщение #11


Гуру
******

Группа: Модератор 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 Текстовая версия Сейчас: 18th July 2025 - 05:09
Рейтинг@Mail.ru


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