Как решить MISRA C: 2012 Правило 11.6? - PullRequest
0 голосов
/ 10 января 2019

Я использую файловую функцию nvmem.c образца Microchip для записи данных в определенный адрес памяти микроконтроллера PIC32. Когда я пытаюсь использовать его, показывая следующую ошибку MISRA: я только что опубликовал пример кода, где я получил ошибку. Весь мой код скомпилирован и работает нормально.

1] явное приведение из «unsigned int» к «void » [MISRA 2012, правило 11.6, обязательно] в NVMemWriteWord ((void ) APP_FLASH_MARK_ADDRESS, (UINT) _usermark);

Как я могу устранить эту ошибку?

nvmem.c
uint8_t NVMemWriteWord(void* address, uint32_t data)
{
    uint8_t res;
    NVMADDR = KVA_TO_PA((uint32_t)address); //destination address to write
    NVMDATA = data;
    res = NVMemOperation(NVMOP_WORD_PGM);
}

test.c
#define ADDRESS 0x9D007FF0U;
NVMemWriteWord((void*)ADDRESS,(uint32_t)_usermark);

Ответы [ 3 ]

0 голосов
/ 10 января 2019

Вся глава 12 MISRA-C: 2012, касающаяся преобразования указателей, довольно требовательна. И это правильно, так как это очень опасная территория.

11.6 - правильное правило, запрещающее преобразование целых чисел в void*. Обоснование заключается в блокировании ошибок выравнивания. Существует не так много причин, почему вы все равно захотите сделать такие преобразования.

Примечательно, что есть также два жестких, но рекомендательных правила 11.4, которые запрещают преобразования из целых чисел в указатели, и 11.5, которые в значительной степени запрещают использование void* полностью. Невозможно заниматься аппаратным программированием и следовать 11.4, поэтому это правило следует игнорировать. Но у вас мало причин использовать void*.

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

В общем случае доступа к регистру необходимо выполнить преобразование с volatile -квалифицированными указателями: (volatile uint32_t*)ADDRESS, при условии, что MCU использует 32-битные регистры.

0 голосов
/ 11 января 2019

Предлагайте:

#define ADDRESS (volatile uint32_t*)0x9D007FF0U
NVMemWriteWord( ADDRESS, _usermark) ;

Никогда не приводить к void* - цель void* состоит в том, что вы можете назначить ему любой другой тип указателя безопасно и без явного приведения. Приведение _usermark может быть или не быть необходимым, но следует избегать ненужных явных приведений - они могут подавлять важные предупреждения компилятора. Вы должны подходить к преобразованию типов в следующем порядке предпочтения:

  • Соглашение о типе - точно такие же типы.
  • Совместимость типов - тип от меньшего к большему, та же подпись.
  • Тип регистра - последнее средство (например, от большого к меньшему типу, несовпадение со знаком, целое число от / до указателя).

В этом случае, поскольку NVMemWriteWord просто приводит address к целому числу, использование void* может быть неуместным. Если в других контекстах вы на самом деле используете указатель, то он может быть действительным.

0 голосов
/ 10 января 2019

Используйте

uint8_t NVMemWriteWord(unsigned int  address, uint32_t data)
{
    uint8_t res;
    NVMADDR = KVA_TO_PA(address);
    NVMDATA = data;
    res = NVMemOperation(NVMOP_WORD_PGM);
}

и

#define  ADDRESS  0x9D007FF0U

NVMemWriteWord(ADDRESS,(uint32_t)_usermark);

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

...