Как вы справляетесь с NUL?
Время от времени я сталкиваюсь с проблемой связи с другими программистами, когда мы говорим о NULL. Теперь NULL может быть
нулевой указатель
NUL персонаж
пустой элемент данных в какой-то базе данных.
NUL кажется наиболее запутанным. Это символ ASCII 0x00.
Я склонен использовать '\0' в своем коде для его представления. Некоторые разработчики в моей группе
как правило, предпочитают просто использовать 0, и пусть компилятор неявно приводит его к типу char.
Что вы предпочитаете использовать для NUL? и почему?
15 ответов
Я использую '\0'
для нуль-символа и NULL
для указателей, потому что это яснее в обоих случаях.
Кстати, оба 0
а также '\0'
являются int
s в 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 есть гораздо более подробная статья, в которой обсуждается эта проблема.
Мне очень нравится
#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'