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

Диагностическое правило основано на руководстве [MISRA](https://misra.org.uk/) \(Motor Industry Software Reliability Association\) по разработке программного обеспечения\.

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

Константа нулевого указателя должна быть получена путём раскрытия макроса [`NULL`](https://en.cppreference.com/w/c/types/NULL.html), определяемого имплементацией стандартной библиотеки, в случаях, когда эта константа:

* присваивается указателю;
* является одним из операндов оператора `!=` или `==`, где другой операнд — это указатель;
* является вторым операндом [conditional operator](https://en.cppreference.com/w/cpp/language/operator_other.html#Conditional_operator) \(`?:`\), где третий операнд это — указатель;
* является третьим операндом conditional operator \(`?:`\), где второй операнд — это указатель\.

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

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

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

```cpp
// 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`\.

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

```cpp
#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}` может быть использован для инициализации объекта агрегатного типа или объединения, содержащего указатели\.

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

```cpp
typedef struct EXAMPLE_STRUCT
{
  void* ptr;
} tExStruct;

tExStruct ya = { 0 };   // ok
```