В чем разница между NULL, '\ 0' и 0

259

В C, по-видимому, существуют различия между различными значениями нуля - NULL, NUL и 0.

Я знаю, что символ ASCII '0' оценивается как 48 или 0x30.

Указатель NULL обычно определяется как:

#define NULL 0

или

#define NULL (void *)0

Кроме того, существует символ NUL '\0', который, как представляется, также оценивается как 0.

Существуют ли случаи, когда эти три значения не могут быть равны?

Это также верно для 64-битных систем?

  • 1
    См. Stackoverflow.com/questions/176989/… для получения дополнительной информации о различиях между 0 и NULL.
  • 7
    Идентификатор NUL не существует в стандартном языке или библиотеке C (или, насколько я знаю, в C ++). Нулевой символ иногда называется NUL, но в C или C ++ его обычно называют просто '\0' .
Теги:
pointers
null

11 ответов

305
Лучший ответ

Примечание.. Этот ответ относится к языку C, а не к С++.


Нулевые указатели

Integer константный литерал 0 имеет разные значения в зависимости от контекста, в котором он использовался. Во всех случаях он по-прежнему является целочисленной константой со значением 0, это просто описано по-разному.

Если указатель сравнивается с константным литералом 0, то это проверка, чтобы увидеть, является ли указатель нулевым указателем. Этот 0 затем называется константой нулевого указателя. Стандарт C определяет, что 0, переданный типу void *, является как нулевым указателем, так и константой нулевого указателя.

Кроме того, для облегчения чтения макрос NULL предоставляется в файле заголовка stddef.h. В зависимости от вашего компилятора возможно #undef NULL и переопределить его на что-то неловкое.

Итак, вот несколько правильных способов проверки нулевого указателя:

if (pointer == NULL)

NULL определяется как сравнимый с нулевым указателем. Реализация определяется, каково фактическое определение NULL, если оно является допустимой константой нулевого указателя.

if (pointer == 0)

0 - это другое представление константы нулевого указателя.

if (!pointer)

Этот оператор if неявно проверяет "не 0", поэтому мы меняем его на "0".

Ниже перечислены НЕВЕРНЫЕ способы проверки нулевого указателя:

int mynull = 0;
<some code>
if (pointer == mynull)

В компилятор это не проверка нулевого указателя, а проверка равенства на две переменные. Это может сработать, если mynull никогда не изменяется в коде, а константа оптимизации компилятора сворачивает 0 в оператор if, но это не гарантируется, и компилятор должен создать хотя бы одно диагностическое сообщение (предупреждение или ошибка) в соответствии со стандартом C.

Обратите внимание, что это нулевой указатель на языке C. Это не имеет значения для базовой архитектуры. Если базовая архитектура имеет значение нулевого указателя, определяемое как адрес 0xDEADBEEF, то компилятор должен сортировать этот беспорядок.

Таким образом, даже в этой смешной архитектуре все еще существуют способы проверки нулевого указателя:

if (!pointer)
if (pointer == NULL)
if (pointer == 0)

Ниже перечислены НЕВЕРНЫЕ способы проверки нулевого указателя:

#define MYNULL (void *) 0xDEADBEEF
if (pointer == MYNULL)
if (pointer == 0xDEADBEEF)

поскольку они рассматриваются компилятором как обычные сравнения.

Нулевые символы

'\0' определяется как нулевой символ - это символ со всеми битами, установленными в ноль. Это не имеет никакого отношения к указателям. Однако вы можете увидеть что-то похожее на этот код:

if (!*string_pointer)

проверяет, указывает ли указатель строки нулевой символ

if (*string_pointer)

проверяет, указывает ли указатель строки на ненулевой символ

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

Кроме того, '\0' является (как и все литералы символов) целочисленной константой, в этом случае с нулевым значением. Итак, '\0' полностью эквивалентен неизмененной константе 0 integer - единственное различие заключается в намерении, которое оно передает человеческому читателю ( "Я использую это как нулевой символ".).

Ссылки

Подробнее см. Вопрос 5.3 часто задаваемых вопросов для comp.lang.c. См. этот pdf для стандарта C. См. Разделы 6.3.2.3 Указатели, пункт 3.

  • 3
    Спасибо за указание на список часто задаваемых вопросов. Однако см. Также c-faq.com/null/nullor0.html.
  • 0
    Хороший вопрос, Синан. Мне никогда не приходило в голову сделать что-то настолько глупое, как использование NULL как целочисленного значения нуля.
Показать ещё 23 комментария
29

Похоже, что многие люди неправильно понимают, какие различия между NULL, '\ 0' и 0. Итак, чтобы объяснить, и в попытке избежать повторения сказанного ранее:

Постоянное выражение типа int со значением 0 или выражение этого типа, отличное от типа void *, является константой нулевой указатель, которая при преобразовании в указатель становится нулевой указатель. Стандартом гарантируется сравнение неравнозначного с любым указателем на любой объект или функцию.

NULL - это макрос, определяемый как константа нулевой указатель.

'\ 0' - это конструкция, используемая для представления символа null, используемого для завершения строки.

A нулевой символ - это байт, у которого все его биты установлены в 0.

  • 7
    +1, даже если быть точным '\ 0' - это символ, определяемый восьмеричным представлением значения. Стандарт определяет '\ N', '\ NN' и '\ NNN' как символьные литералы, представляющие N, NN и NNN в восьмеричном виде.
  • 0
    @ DavidRodríguez-dribeas Я не уверен, что кто-то еще был помешан на нотации, но это очень хорошо проясняет для меня. Просто чтобы быть уверенным, под "представлением" вы подразумеваете "определенный" как в предыдущем предложении?
14

Все три определяют значение нуля в разных контекстах.

  • контекст указателя - используется NULL и означает, что значение указателя равно 0, независимо от того, является ли оно 32-битным или 64-битным (в одном случае 4 байта остальные 8 байтов нулей).
  • string context - символ, представляющий нулевую цифру, имеет шестнадцатеричное значение 0x30, тогда как символ NUL имеет шестнадцатеричное значение 0x00 (используется для завершения строк).

Эти три всегда отличаются друг от друга, когда вы смотрите на память:

NULL - 0x00000000 or 0x00000000'00000000 (32 vs 64 bit)
NUL - 0x00 or 0x0000 (ascii vs 2byte unicode)
'0' - 0x20

Надеюсь, это прояснит это.

  • 7
    Наско: Оцените sizeof('\0') и удивитесь.
  • 2
    @Nasko: Я был действительно удивлен: с gcc, в C: sizeof ('\ 0') == sizeof ('a') == 4, в то время как с g ++, в C ++: sizeof ('\ 0') == sizeof ('a') == 1
Показать ещё 5 комментариев
6

Если NULL и 0 эквивалентны как константы нулевого указателя, которые я должен использовать? в списке часто задаваемых вопросов C также адресует эту проблему:/p >

Программисты

C должны понимать, что NULL и 0 взаимозаменяемы в контексты указателей и что uncast 0вполне приемлемо. Любое использование NULL (в отличие от 0) должен быть считалось нежным напоминанием о том, что указатель; программисты не должен зависеть от него (либо для их собственное понимание или компилятор) для выделения указателя 0 из целого числа 0.

Только в контекстах указателя, NULL и 0 эквивалентны. NULL должен не используется, когда другой вид 0требуется, даже если это может сработать, потому что это делает неправильное стилистическое сообщение. (Кроме того, ANSI позволяет определить NULL ((void *)0), который не будет работать все в контекстах, отличных от указателей.) В в частности, не используйте NULL, когда Нужный символ ASCII (NUL). Укажите свое определение

#define NUL '\0'

если вы должны.

5

В чем разница между NULL, '\ 0 и 0

"нулевой символ (NUL)" проще всего исключить. '\0' является символьным литералом. В C он реализуется как int, поэтому он равен 0, что соответствует INT_TYPE_SIZE. В С++ символьный литерал реализуется как char, который равен 1 байт. Обычно это отличается от NULL или 0.

Далее, NULL - это значение указателя, указывающее, что переменная не указывает на любое адресное пространство. Отмените тот факт, что он обычно реализуется как нули, он должен иметь возможность выразить полное адресное пространство архитектуры. Таким образом, в 32-битной архитектуре NULL (вероятно) имеет 4 байта и 8-разрядную архитектуру с 64-разрядной архитектурой. Это зависит от реализации C.

Наконец, буква 0 имеет тип int, размер которого равен INT_TYPE_SIZE. Значение по умолчанию INT_TYPE_SIZE может отличаться в зависимости от архитектуры.

Apple написала:

64-битная модель данных, используемая Mac OS X, известна как "LP64". Это общая модель данных, используемая другими 64-разрядными системами UNIX от Sun и SGI, а также 64-разрядная Linux. Модель данных LP64 определяет примитивные типы следующим образом:

  • ints - 32-разрядные
  • longs - 64-разрядные
  • long-longs также являются 64-битными
  • указатели 64-разрядные

Википедия 64-бит:

Компилятор Microsoft VС++ использует модель LLP64.

64-bit data models
Data model short int long  long long pointers Sample operating systems
LLP64      16    32  32    64        64       Microsoft Win64 (X64/IA64)
LP64       16    32  64    64        64       Most Unix and Unix-like systems (Solaris, Linux, etc.)
ILP64      16    64  64    64        64       HAL
SILP64     64    64  64    64        64       ?

Edit: Добавлен больше в символьный литерал.

#include <stdio.h>

int main(void) {
    printf("%d", sizeof('\0'));
    return 0;
}

Вышеприведенный код возвращает 4 на gcc и 1 на g++.

  • 2
    Нет, '\0' не является 1-байтовым значением. Это литерой, который представляет собой целое число , константа - так что если можно сказать , чтобы иметь размер , то это размером с int (который должен быть по крайней мере 2 байта). Если вы мне не верите, оцените sizeof('\0') и убедитесь сами. '\0' , 0 и 0x0 полностью эквивалентны.
  • 0
    @caf это зависит от языка. Если вы мне не верите, попробуйте sizeof('\0') на компиляторе C ++.
Показать ещё 1 комментарий
3

Один-L NUL, он заканчивает строку.

Два-L NULL ничего не указывают.

И я поставил золотого быка

Чтобы не было трех-L NULLL.

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

2

Одна хорошая штука, которая помогает мне при запуске с C (взята с помощью Expert C Programming by Linden)

Один 'l' nul и два 'l' null

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

The one "l" NUL ends an ASCII string,

The two "l" NULL points to no thing.

Apologies to Ogden Nash, but the three "l" nulll means check your spelling. 

Символ ASCII с битовой диаграммой нуля называется "NUL". Значение специального указателя, которое означает, что указательный пункт нигде не равен "NULL". Эти два условия не взаимозаменяемы в имея в виду.

  • 0
    Гораздо проще: NUL - это управляющий код, такой как BEL , VT , HT , SOT и т. Д. И, следовательно, имеет макс. 3 персонажа.
2

"NUL" не равен 0, но относится к символу ASCII NUL. По крайней мере, так, как я его видел. Нулевой указатель часто определяется как 0, но это зависит от среды, в которой вы работаете, и от спецификации любой операционной системы или языка, который вы используете.

В ANSI C нулевой указатель указан как целочисленное значение 0. Таким образом, любой мир, где это не так, не соответствует требованиям ANSI C.

0

Байт со значением 0x00 в таблице ASCII имеет специальный символ, называемый "NUL" или "NULL". В C, так как вы не должны вставлять управляющие символы в исходный код, это представлено в строках C с экранированным 0, то есть "\ 0".

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

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

-2

NULL не гарантируется 0 - его точное значение зависит от архитектуры. Большинство основных архитектур определяют его на (void*)0.

'\0' всегда будет равным 0, так как это так, как байт 0 закодирован в символьном литерале.

Я не помню, нужны ли компиляторы C для использования ASCII - если нет, '0' может не всегда равняться 48. Независимо от того, вы вряд ли столкнетесь с системой, которая использует альтернативный набор символов, такой как EBCDIC, если вы работаете над очень неясными системами.

Размеры различных типов будут различаться в 64-битных системах, но целые значения будут одинаковыми.


Некоторые комментаторы выразили сомнение в том, что NULL равен 0, но не равен нулю. Вот пример программы, а также ожидаемый результат в такой системе:

#include <stdio.h>

int main () {
    size_t ii;
    int *ptr = NULL;
    unsigned long *null_value = (unsigned long *)&ptr;
    if (NULL == 0) {
        printf ("NULL == 0\n"); }
    printf ("NULL = 0x");
    for (ii = 0; ii < sizeof (ptr); ii++) {
        printf ("%02X", null_value[ii]); }
    printf ("\n");
    return 0;
}

Эта программа может печатать:

NULL == 0
NULL = 0x00000001
  • 2
    OP спрашивал о «\ 0» (символ NUL), а не «0» (нулевой символ)
  • 1
    C не требует ASCII.
Показать ещё 20 комментариев
-3

(void *) 0 является NULL, а '\ 0' представляет конец строки.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню