Por que as funções de valor absoluto em C não aceitam entradas const?

23

Em C, o protótipo para a função de valor absoluto (que aceita um float) é

 float fabsf( float );

Por que esse protótipo não aceita um valor constante, como este:

 float fabsf( float const );

O fabsf não altera o valor da entrada, altera?

Se eu tiver uma função que aceite uma entrada e chame fabsf, sou forçado a evitar especificar a entrada como const?

Qual é a maneira apropriada de lidar com a correção const nesta situação?

user24205
fonte
26
consté redundante aqui, o que você imagina está acontecendo?
MM
11
@MM Espero que isso crie um erro de tempo de compilação se eu tentar alterar o valor da entrada dentro da função. Isso está incorreto?
user24205
16
Como o parâmetro dentro da função é uma cópia local, a adição consté completamente sem sentido.
Lundin
11
" fabsf não muda o valor da entrada, muda? " Como você poderia dizer? O parâmetro é passado por valor.
David Schwartz
O código a seguir é C legal: float const x = -1.0; float y = fabsf(x);assim parece-me que fabsf faz aceitar entradas const. Não há como dizer "você pode me passar um floatvalor, mas não pode passar um const float". (E como podemos ver nas respostas, C não fornece uma maneira de exigir que a entrada para uma função ser um float const.)
David K

Respostas:

14

Editar

Como MM comentou, nos parâmetros nos protótipos o consté ignorado. A fonte editada da resposta original (veja abaixo) mostra isso:

float correct(float const value);

float erroneous(float const value);

float changer(float value);

float correct(float value) {
  return -value;
}

float erroneous(float value) {
  value = -value;
  return value;
}

float changer(float value) {
    value = -value;
    return value;
}

Não há nenhuma mensagem de erro.

De qualquer forma, deixarei o original no lugar, na esperança de que possa ajudar.


Original

O constparâmetro at torna esse parâmetro somente leitura dentro da função.

Por exemplo:

float correct(float const value) {
  return -value;
}

float erroneous(float const value) {
  value = -value;
  return value;
}

float changer(float value) {
  value = -value;
  return value;
}

Esta fonte não será compilada sem mensagem de erro.

A função correct()lerá o valor fornecido, alterará seu sinal e retornará o valor negado.

A função erroneous()parece efetivamente fazer o mesmo, exceto que há uma atribuição ao parâmetro. Mas, como o parâmetro é, constisso não é permitido.

Em seguida, a função changer()funcionará como as duas anteriores, mas não apresenta erros.

Vejamos o site de chamadas:

float f = 3.14159;
float g = correct(f); // or erroneous(f) or changer(f)

A variável fdada como um argumento será copiado para o parâmetro value. Isso nunca mudará, mesmo que changer()seja chamado.

Você pode considerar os parâmetros como algum tipo de variável local. Na verdade, eles são manipulados dessa maneira no código de máquina gerado.


Então, por que você vê constàs vezes? Você vê se um ponteiro é definido como parâmetro.

Quando você não deseja que o valor apontado seja alterado, é necessário adicionar const; mas faça-o na posição correta!

void effective(int const * pointer);

void futile(int * const pointer);

void possible_but_overly_restricted(int const * const pointer);
the busybee
fonte
A pergunta é sobre protótipos, porém, o protótipo float fabsf( float const );não tem nada a ver com a implementação da função (que não tem de repetir a const), de fato, o consté ignorado inteiramente no protótipo
MM
2
Const pode entrar em definições de função sem entrar no protótipo?
user24205
3
@ user24205 sim ele pode #
Daniel Jour
33

C usa passagem por valor. O valor para o parâmetro de uma função é uma cópia do argumento que você fornece.

Não há problema em copiar flutuações constantes e não constantes, e o resultado é uma flutuação não const.

É semelhante à atribuição:

const float f = 5.5f;
float g = f;   // OK

De fato, a linguagem especifica que o valor de uma expressão nunca pode ser const, ou seja, quando um valor é lido de uma variável, esse valor não é igual constse a variável fosse.

MILÍMETROS
fonte
8

Como a linguagem C usa semântica de passagem por valor, qualquer argumento que você passar para ela, embora possa ser modificado internamente, não afeta diretamente o valor que você passa.

Isto significa que do ponto de vista do autor da chamada, float fabsf( float );e float fabsf( const float );são os mesmos. Portanto, não há sentido em fazer o parâmetroconst .

Onde faz sentido usar consté se o parâmetro que você passa é um ponteiro, por exemplo:

void print_string(char *str)

Esta função, apesar do que o nome sugere, pode desreferenciar o ponteiro especificado e modificar o que aponta, ou seja str[0] = 'x', para resultar em uma alteração visível pela função de chamada. Se esta função foi definida assim:

void print_string(const char *str)

O chamador está garantido de que a função não pode executar nenhuma modificação para o que straponta.

dbush
fonte
"O chamador garante que a função não pode executar nenhuma modificação ..." não é verdade. A função conhece o endereço dos dados e, portanto, pode modificá-lo, com, por exemplo: ((char*)str)[0] = 'f'. A const ... *lista de argumentos é, portanto, apenas uma "declaração de intenção".
oromoiluig
5

Para adicionar uma perspectiva de advogado de idiomas:

Para que dois tipos de função sejam compatíveis, ambos devem especificar tipos de retorno compatíveis. Além disso, as listas de tipos de parâmetros, se ambas estiverem presentes, devem concordar com o número de parâmetros e com o uso do terminador de reticências; parâmetros correspondentes devem ter tipos compatíveis . [..] Na determinação da compatibilidade de tipo e de um tipo composto, [..] cada parâmetro declarado com tipo qualificado é considerado como tendo a versão não qualificada de seu tipo declarado .

N1570 6.7.6.3/15

Isso significa que esses dois são compatíveis:

void foo(int const);
void foo(int);

Portanto, você pode escrever o protótipo com ou sem const(o que significa que sem faz mais sentido; menos digitar / ler) e pode adicionar consta definição de função se desejar evitar modificar acidentalmente o parâmetro (copiado - chamada por valor!) Dentro das funções corpo.

Daniel Jour
fonte