# V2648. MISRA. Null pointer constant must be derived by expansion of the NULL macro provided by the implementation.

Диагностическое правило основано на руководстве MISRA (Motor Industry Software Reliability Association) по разработке программного обеспечения.

Это правило актуально только для C.

Константа нулевого указателя должна быть получена путём раскрытия макроса `NULL`, определяемого имплементацией стандартной библиотеки, в случаях, когда эта константа:

- присваивается указателю;
- является одним из операндов оператора `!=` или `==`, где другой операнд — это указатель;
- является вторым операндом conditional operator (`?:`), где третий операнд это — указатель;
- является третьим операндом conditional operator (`?:`), где второй операнд — это указатель.

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

Примечание. Допускается использование константы нулевого указателя в виде `(void*)0` даже если она не является результатом раскрытия макроса `NULL`.

Пример некорректного кода:

    // Declaring structure in another file
    struct Device {
        void* config;
        int status;
    };

    int updateDevice(struct Device* dev, int newStatus) {
    // ....
    // Here is a large fragment of code...
    // ....
        if (dev == 0) {                  // <=
            return 0;
        }

        if (newStatus == STATUS_RESET) {
            dev->config = 0;             // <=
            dev->status = newStatus;
            return 1;
        }
        return 0;
    }

В примере вместо `NULL` используется константа `0`. На первый взгляд может показаться, что работа происходит с числами, а не с указателями. Для того чтобы избежать неоднозначности в трактовке выражений `dev == 0` и `dev->config = 0`, рекомендуется заменить константу `0` на макрос `NULL` или выражение `(void *)0`.

Корректный код:

    #include <stddef.h>
    int updateDevice(struct Device* dev, int newStatus) {
    // ....
    // Here is a large fragment of code...
    // ....

        if (dev == NULL) {              // ok
            return 0;
        }

        if (newStatus == STATUS_RESET) {
            dev->config = NULL;         // ok
            dev->status = newStatus;
            return 1;
        }
        return 0;
    }

Исключение. Инициализатор `{0}` может быть использован для инициализации объекта агрегатного типа или объединения, содержащего указатели.

Пример корректного кода:

    typedef struct EXAMPLE_STRUCT
    {
      void* ptr;
    } tExStruct;

    tExStruct ya = { 0 };   // ok

Данная диагностика классифицируется как:

MISRA-C-2023-11.9