Ошибка MISRA из-за переноса беззнакового арифметического оператора - PullRequest
0 голосов
/ 13 октября 2019

У меня возникла проблема со стандартами MISRA, связанная с ошибкой обтекания. Я попытался решить ее, изучив доступные в Интернете варианты, но так и не смог ее решить, поскольку не смог найти какое-либо жизнеспособное решение.

Я привожу простой пример, объясняющий мою ситуацию.

У меня ошибка переноса в строке результатов из-за стандартов MISRA. Обтекание в беззнаковой арифметической операции.

Может ли кто-нибудь сообщить мне причину, по которой это происходит, и как справиться с этой ситуацией.

Большое спасибо.

 unsigned int x;
 unsigned int y;
 unsigned int z;
 unsigned int result;

 x= 0;
 y = 60;
 z = 60;

 result = x-y +z;

1 Ответ

2 голосов
/ 14 октября 2019

Как правильно заметил Дитрих Эпп, анализатор кода отмечает, что для заданных значений - которые известны и видны во время компиляции - подвыражение x-y будет математически отрицательным. Отрицательные значения находятся вне диапазона значений беззнаковых типов, они не могут быть представлены;такая ситуация называется переполнением . Это хорошо определено для целых чисел без знака в C ++ (6.7.1 / 4 плюс сноска 45 в стандартном черновике n4713 ) и в C (6.2.5 / 9 в стандартном черновике n1256 ): «Целые числа без знака должны подчиняться законам арифметики по модулю 2 n , где n - число битов в представлении значения."

Арифметика по модулю "оборачивается вокруг". Можно изобразить возможные значения в виде круга, в котором максимальные (все установленные биты) и минимальные (не установленные биты) значения смежны . Как и со всеми другими смежными значениями, я могу переходить от одного к другому, прибавляя или вычитая 1: ((uint8_t)0xff+1 == 0 и соответственно ((uint8_t)0-1 == 0xff. (Битовая комбинация 0xff ... для представления -1 в обычном 2-дополнении известна большинству программистов, но она все же может удивить, когда она возникает в результате вычислений.) В представлении с 2-мя дополнениями этот переход происходит естественным образомпотому что 0xfff... +1 - это 0x10000... с битом переноса, ведущим 1, «слева» от битов в машинном представлении;он просто отбрасывается.

Суть в следующем: возможно, удивительно, что небольшое отрицательное значение, такое как -60, присвоенное беззнаковому int, приводит к большому числу. Это то, о чем вас предупреждает MISRA.

В вашем конкретном случае с указанными значениями проблем не возникает, потому что по модулю арифметическое сложение все еще является обратной операцией к вычитанию независимо от значений, так что 0-60+600. Но проблемы могут возникнуть, если z, скажем, 58, поэтому результат равен -2;это приведет к второму по величине значению, присваиваемому result, которое может содержать его тип. То, что может иметь катастрофические последствия, если, например, значение используется для завершения цикла for. С целыми числами со знаком цикл будет пропущен;с целыми числами без знака оно, вероятно, будет ошибочно работать в течение длительного времени.

После выяснения основной проблемы возникают следующие вопросы:

  1. Как продемонстрировано, вычисления хорошо определеныс беззнаковыми операндами и, с учетом аргументов, имеет неудивительный результат. Довольны ли вы всеми результатами, которые могут произойти с всеми возможными значениями аргументов и комбинациями - то есть, вы довольны модульной арифметикой?

    1a. Да: тогда вопрос в том, хотите ли вы или должны предотвратить предупреждение. Технически тут нечего делать. Любые изменения, вероятно, затенят дело. По-видимому, предупреждения MISRA могут быть подавлены .

    1b. Если это невозможно или желательно, ваш процесс разработки программного обеспечения, скорее всего, будет иметь механизм для квалификации таких предупреждений как приемлемых.

    1c. Если это невозможно или желательно, вам придется (без необходимости) усложнять свой код. Одно из решений состоит в том, чтобы просто выполнить вычисления с 64-разрядными целыми числами со знаком, которые гарантированно смогут хранить все 32-разрядные значения без знака (при условии, что в вашей системе sizeof int == 32), и назначить результат с явным приведением, чтобы указать, что возможноепереполнение и потеря информации являются преднамеренными.

    Или, если в ваших данных всегда сохраняется y < z && x + z < UINT_MAX, вы можете просто изменить порядок оценки на result = x + z - y;, никогда не встретив отрицательных значений в подвыражениях.

  2. Если вы несчастны с модульной арифметикой, особенно с возможностью неожиданно больших результатов, вам придется отступить назад и пересмотреть модель данных, которую вы используете для своей реальноймировые данные. Возможно, вы должны подтвердить свои данные и предотвратить отрицательные результаты, или вы должны использовать целые числа со знаком, или что-то еще не так.

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