为什么C中的绝对值函数不接受const输入?

时间:2019-12-13 04:47:08

标签: c function const pass-by-value

在C语言中,用于绝对值函数(接受浮点数)的原型为

 float fabsf( float );

为什么这个原型不接受一个常量值,像这样:

 float fabsf( float const );

fabsf不会更改输入的值,对吗?

如果我有一个接受输入并调用fabsf的函数,我是否被迫避免将输入指定为const?

在这种情况下处理const正确性的适当方法是什么?

4 个答案:

答案 0 :(得分:33)

C使用按值传递。函数参数的值是您提供的参数的副本。

可以同时复制const和非const浮点数,结果是非const浮点数。

这类似于作业:

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

实际上,该语言指定表达式的值永远不能为const,即,从变量中读取值时,即使该变量为const也不是该值。 / p>

答案 1 :(得分:14)

修改

正如M.M所评论的那样,对于原型中的参数,const被忽略。原始答案的编辑源(如下所示)显示:

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;
}

没有错误消息。

无论如何,我会保留原件,希望对您有所帮助。


原始

参数上的const使该参数在函数内部只读。

例如:

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

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

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

没有错误消息,该源将无法编译。

函数correct()将读取给定值,更改其符号,然后返回取反的值。

函数erroneous()似乎实际上是相同的,只是对参数进行了赋值。但是由于参数为const,因此不允许。

接下来,函数changer()将和以前一样工作,但不会出错。

让我们看一下呼叫站点:

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

作为变量给出的变量f将被复制到参数value中。即使将调用changer(),它也永远不会改变。

您可能希望将参数视为某种局部变量。实际上,它们在生成的机器代码中大多是这样处理的。


那么,为什么有时会看到const?如果将指针定义为参数,就会看到它。

当您不想更改指向的值时,需要添加const;但是要在正确的位置做!

void effective(int const * pointer);

void futile(int * const pointer);

void possible_but_overly_restricted(int const * const pointer);

答案 2 :(得分:8)

由于C语言使用按值传递语义,因此您传递给它的 any 参数虽然可以在内部进行修改,但不会直接影响您传递的值。

这意味着从呼叫者的角度来看,float fabsf( float );float fabsf( const float );是相同的。因此,制作参数const毫无意义。

使用const有意义的地方是void print_string(char *str) ,如果您传入的参数是指针,例如:

str[0] = 'x'

尽管顾名思义,该函数仍可以取消引用给定指针并修改其指向的内容,即void print_string(const char *str) ,以使调用函数可以看到更改。如果此函数的定义如下:

str

确保调用者无法对{{1}}指向的内容进行任何修改。

答案 3 :(得分:5)

要添加语言律师的观点:

  

要使两个函数类型兼容,两者都应指定兼容的返回类型。   此外,参数类型列表(如果同时存在)应在   参数和省略号终止符的使用; 相应参数应具有   兼容类型。   [..]   在确定类型   兼容性和复合类型,[..]每个用限定类型声明的参数   被视为具有声明类型的非限定版本

     

N1570 6.7.6.3/15

这意味着这两个是兼容的:

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

因此,您可以编写带有或不带有const的原型(这意味着没有任何意义;键入/读取的内容更少),并且可以在函数定义中添加const,以避免不必要的修改。函数主体中的(复制-按值调用!)参数。