NULL у мовах програмування Сі і — макрос, оголошений у заголовному файлі stddef.h (та інших заголовних файлах). Значенням цього макроса є залежна від реалізації константа нульового вказівника (англ. null pointer constant).
Константа нульового вказівника — це цілочисельний константний вираз зі значенням 0 або (тільки в Сі) такий самий вираз, але зведений до типу void*
. Константа нульового вказівника, зведена до будь-якого типу вказівників, є нульовим вказівником. Гарантується, що нульовий вказівник не дорівнює вказівнику на будь-який об'єкт (в широкому сенсі слова, будь-які дані) або функцію. Гарантується, що будь-які два нульових вказівники рівні між собою. Розіменування нульового вказівника є операцією з (невизначеною поведінкою).
Інакше кажучи, реалізація надає спеціальне значення — константу нульового вказівника, яку можна присвоїти будь-якому вказівнику і такий вказівник під час порівняння не дорівнюватиме будь-якому «правильному» вказівнику. Тобто, можна вважати, що нульовий вказівник не містить правильної адреси в пам'яті.
Використання Редагувати )
Нульові вказівники придумані як зручний спосіб «позначити» вказівники, які не вказують на правильну адресу в пам'яті. Наприклад, під час оголошення вказівника як автоматичної змінної його значення не визначене. Щоб позначити, що цей вказівник ще не містить правильної адреси в пам'яті, такому вказівнику присвоюють константу нульового вказівника:
void f(void) { int *x = NULL; /* ... */ }
Хорошим стилем програмування є присвоювання вказівнику після вивільнення пам'яті, на яку він посилався, нульового вказівника. Крім цього, застосування обнулення вказівників актуальне для безпеки вивільнення пам'яті: операція в C++ ((free) в Сі) безпечна для нульового вказівника. Наприклад:
TYPE *foo = new TYPE(); // використання foo delete foo;// foo != NULL // якийсь код програми delete foo;// ПОМИЛКА! Память вже недоступна
тоді як у такому варіанті помилки не буде
TYPE *foo = new TYPE(); // використання foo delete foo;// foo != NULL foo = NULL;// foo == NULL // якийсь код програми delete foo;// помилки немає: delete перевіряє значення foo
Розмірність вказівника Редагувати )
Під час виклику функції в один з аргументів можна передати NULL. Макрос NULL у різних компіляторах можна визначити різними способами, зокрема
#define NULL 0
#define NULL ((void *)0)
У першому випадку NULL має тип int, а в другому — тип void*. Існують архітектури, де sizeof (int) != sizeof (void*), тоді на різних платформах до функції надходитиме різна кількість байтів, що може порушити її роботу. Нині робиться спроба вирішити цю проблему в Сі введенням nullptr, див. пропозицію N 2394.
Розіменовування нульових вказівників Редагувати )
Розіменування нульового вказівника є операцією з (невизначеною поведінкою). На реалізацію не накладається жодних обмежень: може статися, наприклад, звернення до пам'яті, не призначеної для використання даною програмою (тобто при читанні буде прочитано «сміття», а при записі — значення потрапить в ділянку пам'яті, що не належить програмі). Наприклад, у DOS запис за нульовою адресою затре принаймні нульовий (вектор переривань), так що наступний виклик int 0 призведе, найпевніш, до зависання системи. Однак найчастіше це призводить до (помилки) часу виконання (якщо в операційній системі реалізовано захист пам'яті і доступ до невиділеної процесу пам'яті блокується). Наприклад, у (Windows 9x) повідомлення «Загальна помилка захисту» — «Програма виконала неприпустиму операцію і буде закрита» (англ. general protection fault, GPF) виводиться найчастіше в тих випадках, коли програма звертається до пам'яті за некоректним (зокрема й неініціалізованим або вже звільненим) вказівником. В (UNIX-подібних операційних системах) у таких ситуаціях процес отримує сигнал (SIGSEGV) і його опрацьовувач виводить повідомлення «(Segmentation fault)».
Нульові вказівники в C++ Редагувати )
Якщо брати конкретну реалізацію NULL за сирцевими файлами, то він може бути визначеним як (void*)0 або як 0. Використання NULL у проектах мовою C++ може призводити до помилок. Наприклад
int (ClassName::*pf)() = NULL;
призведе до помилки компіляції в разі, якщо NULL визначено як (void*)0 (наприклад опосередковано включено заголовок, де стандартне для C++ визначення NULL перекривається). Тому в програмах на C++ не рекомендується використовувати NULL у вигляді ((void*) 0). У стандарті для позначення нульового вказівника додано нове ключове слово (nullptr).
Див. також Редагувати )
- (Помилка сегментації)
- (Варіативна функція)
Примітки Редагувати )
- N 2394. Open Standards (English). оригіналу за 27 липня 2020. Процитовано 22 травня 2020.
- JTC1/SC22/WG21 — The C++ Standards Committee (2 жовтня 2007). SC22/WG21/N2431 = J16/07-0301 «A name for the null pointer: nullptr» (PDF). JTC1.22.32 (англ.). (The C++ Standards Committee). Архів оригіналу за 11 лютого 2012. Процитовано 4 жовтня 2010.(англ.)
Посилання Редагувати )
- Question 5.1. c-faq.com. Архів оригіналу за 26 лютого 2013. Процитовано 2 квітня 2022.
- . c-faq.com. Архів оригіналу за 18 серпня 2011. Процитовано 2 квітня 2022.