exponenta event banner

MISRA C++: 2008 Правило 5-0-16

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

Описание

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

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

Объяснение

Это неопределенное поведение, когда результат арифметической операции указателя, использующей указатель на элемент массива, не указывает ни на одно из следующих действий:

  • Элемент массива.

  • Один за последним элементом массива. Например:

    int arr[3];
    int* res;
    res = arr+3; // res points to one beyond arr

Правило применяется к этим операциям. ptr является указателем на элемент массива и int_exp является целочисленным выражением.

  • ptr + int_exp

  • int_exp + ptr

  • ptr - int_exp

  • ptr + +

  • ++ptr

  • --ptr

  • ptr--

  • ptr [ int_exp ]

Внедрение Polyspace

  • Отдельные объекты, не являющиеся частью массива, считаются массивами одного элемента. Например, в этом примере кода arr_one эквивалентен массиву одного элемента. Polyspace ® не помечает приращение указателяptr_to_one потому что он указывает на один за последним элементом arr_one.

    void f_incr(int* x){
    	int* ptr_to_one = x;
        ++ptr_to_one;  // Compliant
    }
    
    void func(){
    	int arr_one=1; // Equivalent to array of one element
    	f_incr(&arr_one);
    }

  • Polyspace не помечает использование параметров указателя в арифметических операциях указателя, когда указатели указывают на массивы. Например, в этом фрагменте кода использование &a1[2] в f1 совместим при передаче массива в f1.

    void f1( int* const a1){
           int* b= &a1[2]; // Compliant
    }
    void f2(){
    	int arr[3] {};
    	f1(arr);	
    }

  • В структурах с несколькими элементами Polyspace не помечает результат арифметической операции указателя для элемента, которая приводит к указателю, который указывает на другой элемент, если указатель указывает в выделенной памяти структуры или на один мимо последнего элемента структуры.

    Например, в этом фрагменте кода присвоение ptr_to_struct соответствует, потому что он остается внутри myStruct, даже если он указывает наружу myStruct.elem1. Использование индекса, большего, чем измерение элемента, для доступа к содержимому этого элемента несовместимо, даже если результирующий адрес находится в выделенной памяти структуры.

    void func(){
    	struct {
    		char elem1[10];
    		char elem2[10];
    	} myStruct;
    	
    	char* ptr_to_struct = &myStruct.elem1[11]; //Compliant
          // Address of myStruct.elem1[11] is inside myStruct
          char val_to_struct = myStruct.elem1[11]; // Non-compliant
    }

  • В многомерных массивах Polyspace помечает любое использование индексов, которые больше, чем измерение подмассива, для доступа к элементу этого подмассива. Polyspace не помечает назначение адреса того же самого элемента подмассива, если адрес находится в выделенной памяти массива верхнего уровня.

    Например, в этом фрагменте кода назначение указателю ptr_to_arr совместим, поскольку указатель указывает на адрес, который находится в выделенной памяти multi_arr. Присвоение переменной arr_val не соответствует, поскольку индекс, используемый для доступа к элементу (3) подрешетки, больше, чем размер подрешетки (2).

    void func(){
    	int multi_arr[5][2];
    
          // Assigned memory is inside top level array
    	int* ptr_to_arr = &multi_arr[2][3]; //Compliant
    
    	// Use of index 3 with subarray of size 2
    	int arr_val = multi_arr[2][3]; // Non-compliant
    }

  • При указании указателя на один из последних элементов массива полиспейс помечает обратную связь указателя. Например, в этом фрагменте кода назначение ptr соответствует, но отмена ptr не является. tab+3 проходит мимо последнего элемента вкладки.

    void derefPtr(){
    	int tab[3] {};
    	int* ptr = tab+3; //Compliant
    	int res = *(tab+3); // Non-compliant
    }

Поиск неисправностей

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

Примеры

развернуть все

void f_incr(int* x)
{
    int* ptr_to_one = x;
    ++ptr_to_one;  // Compliant
}

void f1(int* const a1)
{
    int* b = &a1[2]; // Compliant
}

int main()
{

    int arr_one = 1; // Equivalent to array of one element
    f_incr(&arr_one);

    int arr[3] {};
    f1(arr);

    struct {
        char elem1[10];
        char elem2[10];
    } myStruct;

    char* ptr_to_struct = &myStruct.elem1[11]; // Compliant
    ptr_to_struct = &myStruct.elem2[11]; //Non-compliant

    int tab[3] {1, 2, 3};
    int* ptr =  &tab[2];
    int res = tab[2];
    ++ptr; // Compliant
    res = *ptr; //Non-compliant

    return 0;
}

В этом примере:

  • Приращение ptr_to_one внутри f_incr() совместим, так как операция приводит к указателю, который указывает на один из последних элементов массива x. Целое число, переданное f_incr() эквивалентен массиву одного элемента.

  • Операция с параметром указателя a1 внутри f1() совместим, поскольку указатель указывает на массив arr.

  • Первое присвоение ptr_to_struct соответствует, потому что elem1[11] все еще находится внутри myStruct. Второе присвоение ptr_to_struct не соответствует, так как результат операции не указывает ни на одно из внутренних myStruct или до одного за последним элементом myStruct.

  • Приращение ptr соответствует, так как результат операции указывает на один за последним элементом tab. Отмена привязки ptr на следующей строке не соответствует.

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

Группа: Выражения
Категория: Обязательно
Представлен в R2021a