[英]Why don't the absolute value functions in C accept const inputs?
在 C 中,绝对值函数(接受浮点数)的原型是
float fabsf( float );
为什么这个原型不接受一个常量值,像这样:
float fabsf( float const );
fabsf 不会改变输入的值,是吗?
如果我有一个接受输入并调用 fabsf 的函数,我是否被迫避免将输入指定为 const?
在这种情况下处理常量正确性的适当方法是什么?
C 使用按值传递。 函数参数的值是您提供的参数的副本。
const 和非常量浮点数都可以复制,结果是非常量浮点数。
它类似于赋值:
const float f = 5.5f;
float g = f; // OK
事实上,该语言规定表达式的值永远不能是const
,即当从变量中读取值时,即使变量是,该值也不是const
。
编辑
正如 MM 所评论的,在原型中的参数上, 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);
因为 C 语言使用按值传递语义,您传递给它的任何参数虽然可以在内部修改,但不会直接影响您传入的值。
这意味着从调用者的角度来看, float fabsf( float );
和float fabsf( const float );
是相同的。 因此,将参数设置为const
毫无意义。
如果您传入的参数是指针,则使用const
确实有意义,例如:
void print_string(char *str)
尽管名称暗示了这个函数,但它可以取消对给定指针的引用并修改它所指向的内容,即str[0] = 'x'
,以导致调用函数可见的更改。 如果这个函数是这样定义的:
void print_string(const char *str)
调用者确保函数不能对str
指向的内容执行任何修改。
要添加语言律师的观点:
对于要兼容的两个函数类型,都应指定兼容的返回类型。 此外,参数类型列表(如果两者都存在)应在参数数量和省略号终止符的使用方面达成一致; 相应的参数应具有兼容的类型。 [..] 在确定类型兼容性和复合类型时,[..]使用限定类型声明的每个参数都被视为具有其声明类型的非限定版本。
N1570 6.7.6.3/15
这意味着这两个是兼容的:
void foo(int const);
void foo(int);
因此,您可以使用或不使用const
编写原型(这意味着不使用更有意义;更少键入/读取)并且如果您想避免意外修改内部的(复制 - 按值调用!)参数,可以在函数定义中添加const
函数体。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.