Devem ser usados ​​​​qualificadores de tipo inúteis em tipos de retorno, para maior clareza?

StackOverflow https://stackoverflow.com/questions/1579435

Pergunta

Nossa ferramenta de análise estática reclama de um "qualificador de tipo inútil no tipo de retorno" quando temos protótipos em arquivos de cabeçalho, como:

const int foo();

Definimos desta forma porque a função está retornando uma constante que nunca mudará, pensando que a API parecia mais clara com const no lugar.

Eu sinto que isso é semelhante a inicializar explicitamente variáveis ​​globais com zero para maior clareza, embora o padrão C já afirme que todos os globais serão inicializados com zero se não forem inicializados explicitamente.No final do dia, isso realmente não importa.(Mas a ferramenta de análise estática não reclama disso.)

Minha pergunta é: há algum motivo para que isso possa causar um problema?Devemos ignorar os erros gerados pela ferramenta ou devemos aplacá-la ao possível custo de uma API menos clara e consistente?(Ele retorna outro const char* constantes com as quais a ferramenta não tem problemas.)

Foi útil?

Solução

Geralmente é melhor que seu código descreva com a maior precisão possível o que está acontecendo.Você está recebendo este aviso porque o const em const int foo(); é basicamente sem sentido.A API só parece mais clara se você não sabe o que const palavra-chave significa.Não sobrecarregue significados assim; static já é ruim o suficiente do jeito que está, e não há razão para acrescentar o potencial para mais confusão.

const char * significa algo diferente de const int faz, e é por isso que sua ferramenta não reclama disso.O primeiro é um ponteiro para uma string constante, o que significa que qualquer código que chame a função que retorna esse tipo não deve tentar modificar o conteúdo da string (pode estar na ROM, por exemplo).Neste último caso, o sistema não tem como garantir que você não faça alterações no valor retornado. int, então o qualificador não tem sentido.Um paralelo mais próximo aos tipos de retorno seria:

const int foo();
char * const foo2();

o que fará com que sua análise estática emita o aviso - adicionar um qualificador const a um valor de retorno é uma operação sem sentido.Só faz sentido quando você tem um parâmetro de referência (ou tipo de retorno), como o seu const char * exemplo.

Na verdade, acabei de fazer um pequeno programa de teste, e o GCC até avisa explicitamente sobre esse problema:

test.c:6: warning: type qualifiers ignored on function return type

Portanto, não é apenas o seu programa de análise estática que está reclamando.

Outras dicas

Você pode usar uma técnica diferente para ilustrar sua intenção sem deixar as ferramentas infelizes.

#define CONST_RETURN

CONST_RETURN int foo();

Você não tem problema com const char * porque isso declara um ponteiro para caracteres constantes, não um ponteiro constante.

Ignorando o const por agora, foo() retorna um valor.Você pode fazer

int x = foo();

e atribua o valor retornado por foo() para a variável x, da mesma maneira que você pode fazer

int x = 42;

para atribuir o valor 42 para a variável x.
Mas você não pode mudar o 42 ...ou o valor retornado por foo().Dizendo que o valor retornado de foo() não pode ser alterado, aplicando o const palavra-chave para o tipo de foo() não realiza nada.

Valores não pode ser const (ou restrict, ou volatile).Somente objetos podem ter qualificadores de tipo.


Contraste com

const char *foo();

Nesse caso, foo() retorna um ponteiro para um objeto.O objeto apontado pelo valor retornado pode ser qualificado const.

O int é retornado por cópia de.Pode ser uma cópia de uma const, mas quando é atribuída a outra coisa, essa coisa, em virtude do fato de ser atribuível, não pode, por definição, ser uma const.

A palavra-chave const possui semântica específica dentro da linguagem, mas aqui você a está utilizando indevidamente, essencialmente como um comentário.Em vez de acrescentar clareza, sugere um mal-entendido da semântica da linguagem.

const int foo() é muito diferente de const char* foo(). const char* foo() retorna um array (geralmente uma string) cujo conteúdo não pode ser alterado.Pense na diferença entre:

 const char* a = "Hello World";

e

const int b = 1;

a ainda é uma variável e pode ser atribuída a outras strings que não podem ser alteradas, enquanto b não é uma variável.Então

const char* foo();
const char* a = "Hello World\n";
a = foo();

é permitido, mas

const int bar();
const int b = 0;
b = bar();

não é permitido, mesmo com a const declaração de bar().

Sim.Eu aconselharia escrever código "explicitamente", porque deixa claro para qualquer pessoa (inclusive você) ao ler o código o que você quis dizer.Você está escrevendo código para outros programadores para ler, para não agradar os caprichos do compilador e das ferramentas de análise estática!

(No entanto, você deve ter cuidado para que qualquer "código desnecessário" não cause a geração de código diferente!)

Alguns exemplos de codificação explícita melhorando a legibilidade/manutenção:

  • Coloco colchetes em torno de partes de expressões aritméticas para especificar explicitamente o que quero que aconteça.Isso deixa claro para qualquer leitor o que eu quis dizer e me poupa de ter que me preocupar com (ou cometer erros com) regras de precedência:

    int a = b + c * d / e + f;      // Hard to read- need to know precedence
    int a = b + ((c * d) / e) + f;  // Easy to read- clear explicit calculations
    

  • Em C++, se você substituir uma função virtual, na classe derivada você poderá declará-la sem mencionar "virtual".Qualquer pessoa que leia o código não poderá dizer que se trata de uma função virtual, o que pode ser desastrosamente enganoso!No entanto, você pode usar com segurança a palavra-chave virtual:

    virtual int MyFunc()
    e isso deixa claro para qualquer pessoa que esteja lendo o cabeçalho da sua classe que esse método é virtual.(Este "bug de sintaxe C++" foi corrigido em C# exigindo o uso da palavra-chave "override" neste caso - mais prova, se alguém precisasse, de que perder o "virtual desnecessário" é uma péssima idéia)

Ambos são exemplos claros de onde adicionar código "desnecessário" tornará o código mais legível e menos sujeito a bugs.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top