Estou tentando limpar algum código C e construir um pacote Debian. O makefile foi configurado para usar -Wall mas debuild usa -Wpedantic .
Acontece que isso foi "uma coisa boa", pois o código estava lançando ponteiros de dados em ponteiros de função (não permitido em ISO C e seriamente perigoso ... em algumas arquiteturas, os dados e o código podem estar em espaços de endereço diferentes)
No entanto, o código também usa intervalos em instruções switch, estas são uma extensão gcc (e clang) e então -Wpedantic dá um ajuste.
case QNAP_PICSTS_SYS_TEMP_0 ... QNAP_PICSTS_SYS_TEMP_70:
(#define não é um enum)
Eu suponho que o uso de intervalos de switch é comum no kernel, eu poderia recodificá-lo para usar um padrão com alguma lógica if/else, mas isso será realmente mais lento (uma tabela de salto versus código)
Então, 1 existe uma opção para permitir apenas esse recurso e 2 (para ganhar pontos extras) como faço para definir isso nas regras do pacote Debian?
As opções estão aqui:
http://gcc.gnu.org/onlinedocs/gcc-4.1.2/gcc/Warning-Options.html
Observei a saída do compilador para switch/case/default onde um grande intervalo é usado; e comparei com o mesmo código implementado em if/else if/else ( código fonte ).
Ele produz exatamente o mesmo código binário, além dos nomes ( compiler explorer de Godbolt ), quando usado com o GCC 12.2 como padrão no debian 12, e com o relevante
dpkg-buildflags
conforme usado pelo debian.Felizmente, um compilador moderno vê coisas simples
if(state == constant) expr; else if(state == other_constant)…
e as converte em tabelas de salto se forem curtas. Então, exatamente o mesmo código do switch/case. Isso já acontece em-O1
, então não é uma otimização atrevida e perigosa.E, além disso, para pouca surpresa, construções como
case 5 ... 74:
são convertidas para uma comparação com 75 (após casos abaixo de 5 já terem sido tratados por uma tabela de salto).Então, realmente, não há razão no código moderno para usar
switch
andcase
, a menos que você ache quecase CONSTANT: … break;
parece mais limpo queif(state == CONSTANT){ … }
. Eu não - e também não acho que o seu compilador: ter blocos permite um escopo mais rigoroso.Há uma exceção, e é claro que
case:
sembreak
permite que você basicamente emulegoto
semgoto
:é equivalente ao hipotético
(e nós dois conhecemos os bugs que o esquecimento
break;
trará; são os mesmos problemas que o usogoto
trará se você não tomar muito cuidado.)Espero que você veja como
switch
é realmente uma construção conveniente para pessoas que constroem máquinas de estados finitos e não deve ser usada com intervalos - simplesmente não há vantagem em um compilador que não seja antigo em comparação com , e grandes fontesif/else if
de bugs em fluxo de controle não óbvio .Assim, acho que, com a retrospectiva sendo forte e com o conhecimento das otimizações do compilador moderno sendo bom, eu diria que o recurso de
case
intervalos do GNU foi mal concebido e, portanto, o aviso é sensato.Chego , portanto, à conclusão de que a maneira correta de silenciar esse aviso é uma conversão do seu //
switch
para uma construção // .case
default
if
else if
else