Нет предупреждения компилятора из-за непоследовательного использования параметра функции - PullRequest
0 голосов
/ 23 января 2019

Во время проверки кода C программного обеспечения, которое не хотело запускаться на целевом HW, при использовании функции было обнаружено следующее несоответствие:

Компонент 1 ПО реализует функцию:

void foo(uint8 par_var[2])

Функция foo() также записывает два элемента массива par_var.

Компонент SW 2 получает внешнюю декларацию функции foo () следующим образом

extern void foo(uint8 *par_var)

и использует его следующим образом:

uint8 par_var;

foo(&par_var); //-> sending a pointer to a scalar
               //   instead to an array of 2 elements.

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

Вопрос в том, может ли компилятор / компоновщик перехватить несоответствие, например, выдав предупреждение.

Я отсканировал и попробовал некоторые параметры компилятора gcc (CygWin) вместе со стандартными (-Wall, -pedantic) https://gcc.gnu.org/onlinedocs/gcc-3.4.4/gcc/Warning-Options.html

но не смог найти тот, который мог бы выдать соответствующее предупреждение.

1 Ответ

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

Существует функция C, которая может помочь компилятору в диагностике этого, но я не знаю о компиляторе, который использует это и предупреждает. Если foo было объявлено как void foo(uint8 par_var[static 2]);, то вызывающая сторона должна передать указатель как минимум на два элемента, согласно C 2018 6.7.6.3 7:

Если ключевое слово static также присутствует в [ и ] деривации типа массива, то при каждом вызове функции значение соответствующего фактического аргумента должно обеспечивать доступ к первому элементу массив, содержащий как минимум столько же элементов, сколько указано в выражении размера.

Таким образом, компилятор, увидевший uint8 par_var; foo(&par_var);, может распознать сбой передачи двух элементов и выдать предупреждение. (Хотя мне не известны компиляторы, которые проверяют объявленный размер, некоторые компиляторы будут предупреждать, когда для такого параметра передается нулевой указатель.)

Как известно, в объявлении void foo(uint8 par_var[2]), par_var автоматически устанавливается на uint8 *par_var. В качестве альтернативы, вместо передачи указателя на uint8, вы можете передать указатель на массив uint8, объявив foo как void foo(uint8 (*par_var)[2]);.

Тогда вам нужно будет передать ему массив, например:

uint8 A[2];
foo(&A);

Если он был вызван с указателем на uint8, компилятор должен выдать предупреждение. К сожалению, это также ограничивает рутину; Вы должны передать ему указатель на массив из двух uint8 и не можете передать ему указатель на массив большего размера или указатель на uint8 в массиве большего размера. Так что он имеет ограниченное использование. Тем не менее, он может служить в определенных ситуациях.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...