Как бороться с предупреждениями -Wconversion от GCC?
-
10-07-2019 - |
Вопрос
Я создаю свой проект с флагом предупреждения GCC -Wconversion.(gcc (Debian 4.3.2-1.1) 4.3.2) на 64-битной ОС/оборудовании GNU/Linux.Я нахожу это полезным для определения того, где я перепутал типы или потерял ясность относительно того, какие типы следует использовать.
Это не очень полезно в большинстве других ситуаций, которые активируют его предупреждения, и я спрашиваю, как мне с ними справиться:
enum { A = 45, B, C }; /* fine */
char a = A; /* huh? seems to not warn about A being int. */
char b = a + 1; /* warning converting from int to char */
char c = B - 2; /* huh? ignores this *blatant* int too.*/
char d = (a > b ? b : c) /* warning converting from int to char */
В связи с неожиданными результатами вышеуказанных испытаний (случаи a
и c
) Я тоже прошу объяснить эти различия.
Редактировать:И не является ли это чрезмерным инженерным трудом — приводить все это к (char)
предотвратить предупреждение?
Редактировать2:Некоторые дополнительные случаи (следующие из приведенных выше случаев):
a += A; /* warning converting from int to char */
a++; /* ok */
a += (char)1; /* warning converting from int to char */
Кроме того, то, о чем я спрашиваю, является субъективным, и мне хотелось бы услышать, как другие люди справляются с предупреждениями о конверсиях в подобных случаях, если учесть, что некоторые разработчики выступают за удаление все предупреждения.
ЯЭ:
Одним из возможных решений является просто использовать int
s вместо char
верно?На самом деле, он не только требует больше памяти, но и медленнее, как это демонстрирует следующий код.Математические выражения нужны только для того, чтобы получать предупреждения при построении с помощью -Wconversion
.Я предположил версию, используя char
переменные будут работать медленнее, чем при использовании int
Это из-за преобразований, но в моей (64-битной двухъядерной системе II) система int
версия медленнее.
#include <stdio.h>
#ifdef USE_INT
typedef int var;
#else
typedef char var;
#endif
int main()
{
var start = 10;
var end = 100;
var n = 5;
int b = 100000000;
while (b > 0) {
n = (start - 5) + (n - (n % 3 ? 1 : 3));
if (n >= end) {
n -= (end + 7);
n += start + 2;
}
b--;
}
return 0;
}
Проходить -DUSE_INT
в gcc для создания int-версии приведенного выше фрагмента.
Решение
Когда ты говоришь /* int */
Вы имеете в виду, что он предупреждает вас об этом?Я вообще не вижу никаких предупреждений в этом коде с gcc 4.0.1 или 4.2.1 с -Wconversion
.Компилятор преобразует эти перечисления в константы.Поскольку все известно во время компиляции, нет смысла генерировать предупреждение.Компилятор может оптимизировать всю неопределенность (это Intel с версией 4.2.1):
movb $45, -1(%rbp) # a = 45
movzbl -1(%rbp), %eax
incl %eax
movb %al, -2(%rbp) # b = 45 + 1
movb $44, -3(%rbp) # c = 44 (the math is done at compile time)
movzbl -1(%rbp), %eax
cmpb -2(%rbp), %al
jle L2
movzbl -2(%rbp), %eax
movb %al, -17(%rbp)
jmp L4
L2:
movzbl -3(%rbp), %eax
movb %al, -17(%rbp)
L4:
movzbl -17(%rbp), %eax
movb %al, -4(%rbp) # d = (a > b ? b : c)
Это без включения оптимизации.Благодаря оптимизации он рассчитает b и d для вас во время компиляции и жестко запрограммирует их окончательные значения (если они действительно нужны ему для чего-либо).Дело в том, что gcc уже понял, что здесь не может быть проблем, потому что все возможные значения укладываются в char
.
РЕДАКТИРОВАТЬ:Позвольте мне несколько исправить это.Возможна ошибка в назначении b
, и компилятор никогда его не поймает, даже если это точно.Например, если b=a+250;
, то это обязательно переполнится b
но gcc не выдаст предупреждение.Это потому, что задание a
является законным, a
это char
, и ваша проблема (а не компилятора) — убедиться, что математические вычисления не переполняются во время выполнения.
Другие советы
Возможно, компилятор уже видит, что все значения умещаются в символ, поэтому его не беспокоит предупреждение.Я ожидаю, что enum
нужно решить в самом начале компиляции.