Допустимо ли присваивать NULL логический тип данных? - PullRequest
4 голосов
/ 16 марта 2009

Допустимо ли присваивать NULL логический тип данных?

Ответы [ 12 ]

10 голосов
/ 16 марта 2009

С теоретической точки зрения да. Но это ужасная вещь.

NULL - это константа нулевого указателя, которая назначается указателю, чтобы он ни на что не указывал.

...
ptr = NULL; // now it points to no object anymore
...

// or ptr == 0
if(ptr == NULL) {
    ...
}

Вот ссылки на Стандарт, если вы заинтересованы в любом случае. Во-первых, константа нулевого указателя: (4.10/1)

Константа нулевого указателя - это целочисленное константное выражение (5.19) r целого типа, которое оценивается как ноль.

Тогда что произойдет, если мы преобразуем константу нулевого указателя в bool? Это объясняется в 4.12/1:

Значение r арифметики, перечисления, указателя или указателя на тип члена может быть преобразовано в значение типа bool. Нулевое значение, нулевое значение указателя или нулевое значение указателя члена преобразуется в ложь; а

(когда речь идет о rvalue, это, по сути, означает простое значение, а не переменную этого типа).

Теперь, что на самом деле является , что NULL? Прочитайте 18.1/4 (обратите внимание, что в C константа нулевого указателя определяется по-другому. Возможно, именно поэтому она явно ссылается на C ++)

Макрос NULL является константой нулевого указателя C ++, определяемой реализацией в этом международном стандарте

Важным битом этой комбинации является часть "A zero value ... is converted to false". Присвоение NULL переменной bool попытается преобразовать NULL в логическое значение. Как сказано в приведенных выше отрывках, такое преобразование существует и может быть сделано.

Еще одна важная вещь о нулевых указателях для понимания - это различия между null pointer и null pointer constant. Как мы только что прочитали, константа нулевого указателя - это некое целое значение, равное нулю. Однако, null pointer и его значение, null pointer value, являются указателями, а их тип имеет тип указателя. Следующее имеет тип int и является константой нулевого указателя

#define NULL ('n'-'n') // looks suspicious, but conforms

Потому что это целочисленное константное выражение (то есть целочисленное значение, которое известно во время компиляции) со значением ноль. Ниже приведено нулевое значение указателя

(void*)NULL

но это не константа нулевого указателя. Но в любом случае, также нулевой указатель значения преобразуются в bool, как указано в приведенной выше цитате: "A .. null pointer value .. is converted to false". Так что у тебя все хорошо.

5 голосов
/ 16 марта 2009

Из моей копии n2798:

18,1 Типы

3 Макрос NULL является константой нулевого указателя C ++, определенной реализацией, в этом международном стандарте (4.10)

и

4.12 Булевы преобразования [conv.bool]

1 Значение арифметики, перечисление с незаданной областью, указатель или указатель на тип члена может быть преобразовано в значение типа bool. Нулевое значение, нулевое значение указателя или нулевое значение указателя члена преобразуется в ложь; любое другое значение преобразуется в true. Значение типа std :: nullptr_t может быть преобразовано в значение типа bool; Полученное значение равно false.

Так что, да, похоже, что вы можете сделать это.

2 голосов
/ 16 марта 2009

Мое мнение таково, что это снизит читабельность вашего кода, но обязательно, если вы захотите. В конце концов, NULL равно 0.

2 голосов
/ 16 марта 2009

Компилятор не будет отклонять его, поскольку NULL обычно является препроцессором #define для 0, а 0 преобразуется в представление указателя NULL и false.

1 голос
/ 16 марта 2009

Даже если это технически возможно сделать, я бы избежал этого. Кажется, что если вам нужно нулевое значение, вам следует смоделировать тип данных, отличный от логического.

Если вы собираетесь использовать Boolean, правильно спроектируйте свой модуль и код, чтобы использовать его в соответствии с назначением: с двумя потенциальными значениями, а не с тремя. Если вам нужно три, используйте другой тип данных, например, int или string, и каждое из трех значений должно что-то значить (в строке null строка будет означать null).

1 голос
/ 16 марта 2009

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

int *i = NULL;
if (i) // This is a pretty acceptable use of pointer conversions to bool
{
   // never runs.
}

или

int *i = NULL;
...
bool b = i; // Maybe not so terrible, but you're better off just assigning to a pointer.

Это сделано специально (см. Ответ dirkgently для стандартной ссылки), чтобы разрешить такое использование. Если вы используете этот синтаксис:

bool i = NULL; // Don't do this
bool i2 = 0; // better
bool i3 = false; // Best

Тогда вы, вероятно, вводите в заблуждение, но это будет работать переносимым, предсказуемым образом. Либо NULL определено как 0, в этом случае вы получите ложное значение, или, если NULL действительно является указателем NULL, тогда оно также будет иметь значение false.

0 голосов
/ 16 марта 2009

Вы можете сделать это, но я не вижу смысла. Предположим, у вас есть:

void* p = NULL;
bool b = p;

Почему бы просто не написать это как:

void* p = NULL;
bool b = (p != NULL);

Это понятнее, и любой достойный компилятор сгенерирует тот же код.

0 голосов
/ 16 марта 2009

NULL не по определению 0. Я не знаю ни одного, но могут быть некоторые компиляторы, которые используют ненулевое значение для NULL или, возможно, даже устанавливают какой-то флаг в thunk за его адресом. Будет только вашей удачей, что ваш код будет перенесен на один из них. Было бы просто моей удачей, что мне пришлось бы исправить возникающие ошибки.

Поэтому я говорю: «Нет, это не приемлемо».

0 голосов
/ 16 марта 2009

Поскольку NULL обычно не 0, а (void*)0, он не работает так же, как в C ++, поскольку в этом случае NULL является указателем. Вам бы пришлось сделать явное приведение: reinterpret_cast<bool>(NULL), и нет, это не чисто. Вы должны использовать true / 1 и false / 0

0 голосов
/ 16 марта 2009

Я не уверен, почему ты хочешь это сделать. Если вы пытаетесь инициализировать его, используйте 0. Как сказал MSN, ваш компилятор не собирается отклонять его. Возможно, вам следует объяснить, почему вы хотите установить bool в NULL?

...