MISRA C:2012 Rule 18.4

Операторы +, -, + = и - = не должны применяться к выражению типа указателя

Описание

Определение правила

Операторы +, -, + = и - = не должны применяться к выражению типа указателя.

Объяснение

Предпочтительной формой арифметики указателя является использование синтаксиса индекса массива ptr[expr]. Этот синтаксис ясен и менее подвержен ошибкам, чем манипуляции с указателем. При манипуляции указателем любое явно вычисленное значение указателя может получить доступ к непреднамеренным или недопустимым адресам памяти. Индексация массивов также может получить доступ к непреднамеренной или недопустимой памяти, но ее легче просмотреть.

Новому программисту на C выражение ptr+1 может быть ошибочно истолкован как один плюс адрес ptr. Однако новый адрес памяти зависит от размера, в байтах, цели указателя. Эта путаница может привести к неожиданному поведению.

При использовании с осторожностью, манипуляция указателями с помощью ++ может быть более естественным (для образца, последовательно получая доступ к местоположениям во время тестирования памяти).

Реализация Polyspace

Polyspace® операции флагов для указателей, например Pointer + Integer, Integer + Pointer, Pointer - Integer.

Поиск и устранение проблем

Если вы ожидаете нарушения правил, но не видите его, обратитесь к разделу «Стандартные нарушения кодирования не отображаются».

Примеры

расширить все

void fun1(void){
    unsigned char arr[10];
    unsigned char *ptr;
    unsigned char index = 0U;
    
    index = index + 1U;   /* Compliant - rule only applies to pointers */
    
    arr[index] = 0U;      /* Compliant */
    ptr = &arr[5];        /* Compliant */
    ptr = arr;
    ptr++;                /* Compliant - increment operator not + */
    *(ptr + 5) = 0U;      /* Non-compliant */
    ptr[5] = 0U;          /* Compliant */
}

В этом примере показаны различные операции с указателями и массивами. Единственная операция в этом примере, которая не совместима, - это использование + оператор непосредственно с указателем (линия 12).

void fun2(void){
    unsigned char array_2_2[2][2] = {{1U, 2U}, {4U, 5U}};
    unsigned char i = 0U;
    unsigned char j = 0U;
    unsigned char sum = 0U;
    
    for(i = 0u; i < 2U; i++){
        unsigned char *row = array_2_2[ i ];
        
        for(j = 0u; j < 2U; j++){
            sum += row[ j ];                   /* Compliant */    
        }
    }        
}

В этом примере второй for в цикле используется указатель на массив row в арифметическом выражении. Однако это использование совместимо, поскольку в нем используется форма индекса массива.

void fun3(unsigned char *ptr1, unsigned char ptr2[ ]){
    ptr1++;               /* Compliant */
    ptr1 = ptr1 - 5;      /* Non-compliant */
    ptr1 -= 5;            /* Non-compliant */
    ptr1[2] = 0U;         /* Compliant */
    
    ptr2++;               /* Compliant */
    ptr2 = ptr2 + 3;      /* Non-compliant */
    ptr2 += 3;            /* Non-compliant */
    ptr2[3] = 0U;         /* Compliant */
}

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

Если ptr1 не указывает на массив с по крайней мере шестью элементами и ptr2 не указывает на массив с по крайней мере 4 элементами, этот пример нарушает правило 18.1.

Проверяйте информацию

Группа: указатели и массивы
Категория: Консультационные
Категория СМЖЛ: Консультационная