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

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

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

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

#define NULL 0

или

#define NULL (void *)0

кроме того, есть NUL символ '' который, кажется, оценивает 0 как хорошо.

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

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

11 ответов


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


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

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

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

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

таким образом, вот несколько допустимых способов проверить значение 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)

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

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

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

if (!*string_pointer)

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

if (*string_pointer)

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

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

кроме того, '' является (как и все символьные литералы) целочисленной константой, в этом случае со значением ноль. Так что '' полностью эквивалентно unadorned 0 целочисленная константа-единственная разница в намерение что он передает человеческому читателю ("я использую это как null характер.").

ссылки

посмотреть вопрос 5.3 комп.ленг.C FAQ дополнительные. См.этот pdf для стандарта C. Ознакомьтесь с разделами 6.3.2.3 указатели, пункт 3.


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

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

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

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

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


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

  • контекст указателя-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

Я надеюсь, что это проясняет его.


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

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

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

#define NUL ''

если нужно.


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

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

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

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

Apple написал:

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

  • ints 32-бит
  • длинные 64-битные
  • длинные-длинные также 64-разрядные
  • указатели 64-битные

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

компилятор Microsoft VC++ использует модель 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       ?

редактировать: Добавлено больше символов литерала.

#include <stdio.h>

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

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


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

a two-L NULL указывает ни на что.

и я поставлю золотой бык

что нет трех-L NULLL.

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


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

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


один хороший кусок, который помогает мне при запуске с C (взято из экспертного программирования C Линденом)

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

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

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". Эти два термина не являются взаимозаменяемыми в значение.


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

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

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


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

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