Как исправить ошибки, вызванные -Wconversion? - PullRequest
3 голосов
/ 09 января 2020

У меня есть кусок подделка / образец код:

#include <stdint.h>

uint8_t func(uint16_t val0, uint16_t val1, uint16_t val2)
{
    uint8_t r;
    val0 += 0x7F;
    val1 += (uint16_t)0x7F;
    val2 += 0x7FU;
    r = (uint8_t)((val0+val1+val2) >> 8);
    r <<= (uint8_t)(val2 & 0x3);
    return r;
}

Вот ошибки, которые я получаю:

$ gcc -Wall -Wextra -Wconversion -O0 module.c -c -o module.o 
module.c: In function 'func':
module.c:6:10: warning: conversion from 'int' to 'uint16_t' {aka 'short unsigned int'} may change value [-Wconversion]
    6 |  val0 += 0x7F;
      |          ^~~~
module.c:7:10: warning: conversion from 'int' to 'uint16_t' {aka 'short unsigned int'} may change value [-Wconversion]
    7 |  val1 += (uint16_t)0x7F;
      |          ^
module.c:8:10: warning: conversion from 'unsigned int' to 'uint16_t' {aka 'short unsigned int'} may change value [-Wconversion]
    8 |  val2 += 0x7FU;
      |          ^~~~~
module.c:10:8: warning: conversion from 'int' to 'uint8_t' {aka 'unsigned char'} may change value [-Wconversion]
   10 |  r <<= (uint8_t)(val2 & 0x3);
      |        ^

В примере показаны некоторые способы, которыми я пытался решить проблему (например, приведение)

Любое предложение?

РЕДАКТИРОВАТЬ:

модифицированный пример

Ответы [ 2 ]

8 голосов
/ 09 января 2020

Этот вопрос иллюстрирует, почему -Wconversion настолько переусердствовал, что в значительной степени бесполезен.

В C нет арифметических значений c меньше, чем int. Например:

val0 += 0x7F;

оценивается так, как если бы это было

val0 = (int)val0 + 0x7F;

Присвоение обратно val0 без приведения, затем запускает -Wconversion. В некотором смысле это законное предупреждение: оператор + не переполняется, но возвращение результата может потерять часть результата, и компилятор скажет вам об этом (хотя и неловко).

Если вы Если вы собираетесь использовать -Wconversion, вы по существу не можете использовать составной оператор присваивания (например, +=) с типами, меньшими чем * int. Вам нужно выписать эквивалентную форму и использовать приведение, чтобы указать, что вы намерены провести преобразование с потерями. Например, здесь вы могли бы написать:

val0 = (uint16_t)(val0 + 0x7F);

Я не думаю, что это ужасно хороший стиль, но некоторые стандарты / политики кодирования (я думаю, MISRA, например) требуют его.

2 голосов
/ 09 января 2020

Кастинг / битовые маски могут помочь.

Например,

#include <stdint.h>

uint8_t func(uint16_t val0, uint16_t val1, uint16_t val2)
{
    unsigned int r;
    val0 = (uint16_t)(val0 + 0x7Fu);
    /*val0 = (val0 + 0x7Fu) & 0xFFFF;*/
    val1 = (val1 + 0x7Fu) & 0xFFFF;
    val2 = (val2+0x7FU) & 0xFFFF;
    r = ((0u+val0+val1+val2) >> 8);
    r = ( r << (uint8_t)(val2 & 0x3u)) & 0xFF;
    return r&0xFF;
}

Возможно, будет хорошей идеей попытаться избежать типов короче, чем int. Из-за целочисленных повышений (целочисленные типы sub-int повышаются до int), они приводят к большому количеству -Wconversion предупреждений.

...