Как вы справляетесь с NUL?

Время от времени я сталкиваюсь с проблемой связи с другими программистами, когда мы говорим о NULL. Теперь NULL может быть

нулевой указатель
NUL персонаж
пустой элемент данных в какой-то базе данных.


NUL кажется наиболее запутанным. Это символ ASCII 0x00.
Я склонен использовать '\0' в своем коде для его представления. Некоторые разработчики в моей группе
как правило, предпочитают просто использовать 0, и пусть компилятор неявно приводит его к типу char.


Что вы предпочитаете использовать для NUL? и почему?

15 ответов

Решение

Я использую '\0' для нуль-символа и NULL для указателей, потому что это яснее в обоих случаях.

Кстати, оба 0 а также '\0' являются ints в C, и любой из них будет преобразован в char когда хранится в char переменная.

Мне нравится предопределенный макрос NULL, так как он сохраняет семантическое значение, а не какое-либо другое использование числа 0.

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

  • Для работы со строками я всегда представляю нулевой символ как '\0'.
  • Для указателей я пытаюсь использовать неявное преобразование в логическое (if (! MyPtr) или if (myPtr)) для нулевого указателя.
  • Если мне нужно значение по умолчанию для указателя, это NULL, например, struct list_head = {0.0, NULL};).

END_OF_STRING - глупость, так как это дополнительная косвенность, которая просто сбивает с толку новых читателей (любой, кто не сразу распознает '\ 0', должен отойти от клавиатуры).

Еще одна вещь - я думаю, что разница между нулевым значением и пустым значением чрезвычайно важна, когда речь идет о моделировании данных. Это особенно верно при обсуждении строк в стиле C или обнуляемых полей базы данных. Существует огромная разница между тем, кто говорит вам: "У меня нет имени" и "Меня зовут".

@BKB:

Я вижу смысл в его совете, но "NULL" проясняет, что контекст - это указатели. Это похоже на использование "0.0" для значений с плавающей точкой, как "\0" при работе с символами. (Аналогично, я предпочитаю видеть 0, если символ используется в арифметическом контексте.)

Bjarne далее заявляет в этом FAQ, что NULL в любом случае имеет значение # 0, поэтому у стандартного кода не должно быть проблем с ним. Я согласен с тем, что нотация всех заглавных букв уродлива, но нам придется подождать до 0x (где в качестве ключевого слова будет доступен nullptr).

A one-L NUL, it ends a string. 
A two-L NULL points to no thing. 
And I will bet a golden bull 
That there is no three-L NULLL. 



(The name of the original author is, alas, lost to the sands of time.)

Если я правильно помню, большинство компиляторов C определяют NULL следующим образом:

#define NULL ((void*)0)

Это должно гарантировать, что NULL интерпретируется как тип указателя (в C). Однако это может вызвать проблемы в гораздо более строгом мире C++. Например:

// Example taken from wikibooks.org
std::string * str = NULL; // Can't automatically cast void * to std::string *
void (C::*pmf) () = &C::func;
if (pmf == NULL) {} // Can't automatically cast from void * to pointer to member function.

Поэтому в текущем стандартном C++ нулевые указатели должны быть инициализированы литералом 0. Очевидно, потому что люди так привыкли использовать определение NULL, я думаю, что многие компиляторы C++ либо игнорируют проблему, либо переопределяют NULL на 0 в коде C++. Например:

#ifdef __cplusplus
#define NULL (0)
#else
#define NULL ((void*)0)
#endif

Стандарт C++x0 теперь определяет nullptr Ключевое слово для представления нулевых указателей. Компилятор CLI / C++ в Visual C++ 2005 также использует это ключевое слово при установке для управляемых указателей значения NULL. В текущих компиляторах вы можете создать шаблон для эмуляции этого нового ключевого слова.

На wikibooks.org есть гораздо более подробная статья, в которой обсуждается эта проблема.

NULL для баз данных, NIL для кода.

Мне очень нравится

#define ASCII_NUL ('\0')

Я только очень иногда неправильно набираю '\0' как '0'. Но когда я это сделал, я обнаружил, что ошибку очень трудно обнаружить с помощью проверки кода, что приводит к смешным последствиям. Поэтому я не очень люблю '\0' и предпочитаю ASCII_NUL или 0 (конечно, последний имеет неправильный тип в C++). Очевидно, я использую '\0' там, где этого требует согласованность с существующим кодом или руководствами по стилю.

Руководство по стилю Google C++, которое содержит несколько вещей, которые мне нравятся, и некоторые, которые мне не нравятся, но в основном звучит здраво, предпочитает от 0 до 0 для указателей. Это указывает на то, что NULL не может быть определен просто как 0 (или 0L), особенно в реализациях, где sizeof(void*) не может быть sizeof(int) (или sizeof (long int)).

0 и NULL оба имеют целочисленный тип, и при преобразовании в тип указателя они оба должны давать нулевое значение указателя. Но они не обязательно одного и того же интегрального типа. Таким образом, вы можете получить некоторые полезные предупреждения или ошибки в некоторых ситуациях, используя NULL.

Хотя в целом я бы посоветовал использовать именованные константы, это одно исключение. Для меня определение:

#define NULL 0
#define END_OF_STRING '\0'

имеет столько же смысла, сколько определение:

#define SEVEN 7

которого нет И да, я знаю, что NULL уже определен компилятором, но я никогда не использую его. Для указателей 0; для символов '\0'. Более длинный не всегда означает более выразительный.

Вроде как: у Slashdot недавно была история о comp.lang.c Раздел FAQ по нулевым указателям, который мне показался довольно интересным.

Системы, которые не используют двоичный 0 для NULL, становятся все труднее найти. Они также имеют тенденцию иметь различные проблемы с переносимостью. Зачем? Потому что в этих системах ни memset, ни calloc не могут очистить структуру, которая правильно содержит указатели.

Для общения я использую NULL. Если я работаю с разработчиком, который не может понять концепцию NULL для разных типов данных, то я буду обеспокоен.

Для реализации это зависит от конкретного случая. Числа равны 0 (постфиксное f для плавающей запятой), указатели равны NULL, а строки символов равны 0.

const char END_OF_STRING = '\0';

Поэтому, когда вы говорите:

str[i] = END_OF_STRING;

или же

if (*ptr == END_OF_STRING)

нет никаких сомнений в том, что вы имеете в виду.

Мы используем NULL для указателей и NULLCHAR для символов, используя

#define NULLCHAR '\0'
Другие вопросы по тегам