[英]Why does sqrt() work fine on an int variable if it is not defined for an int?
在《 编程:使用C ++的原理和实践》 (第六次印刷)的第3章中,Stroustrup指出(第68页): “请注意,没有为int
定义sqrt()
” 。
这是基于该章的简单C ++程序:
#include "std_lib_facilities.h"
int main()
{
int n = 3;
cout << "Square root of n == " << sqrt(n) << "\n";
}
鉴于以上引用,我希望编译或运行该程序的过程会在某种程度上失败。
令我惊讶的是,使用g ++(GCC(GCC)4.2.1)对其进行编译并运行成功,没有出现错误或警告,并产生了以下完美的输出:
Square root of n == 1.73205
因此,我的问题是:如果sqrt()
确实没有为int
定义,那么上面的程序为什么不以某种方式失败?
10正在隐式转换为double。 只要您具有sqrt的正确函数原型,此操作就会自动发生。
编辑:被评论打败
更新2
将这个问题与一个完全重复的问题合并在一起,看看这个问题,实际答案比任何人最初想的都要简单得多。 当前版本的std_lib_facilities.h包含以下行:
inline double sqrt(int x) { return sqrt(double(x)); } // to match C++0x
这会为int情况创建一个特定的重载,以匹配现代编译器应做的工作,即将整数参数转换为double ,尽管此版本未涵盖所有情况。
如果未使用std_lib_facilities.h ,则原始逻辑仍然适用,尽管从原始问题来看,与Visual Studio 2012相比, gcc-4.2
已经相当老了,但是4.1.2
版本使用__builtin_sqrt
专门用于整数情况。
原版的
从2005年左右开始 ,标准草案要求将整数参数强制转换为两倍,这在C ++标准草案中已涉及。 如果我们看一下第26
库 ,然后转到第26.8
节C库 ,它覆盖了<cmath>
标头,它指定了float , double和long double的数学函数的重载,这在第8段中进行了介绍:
除了中的数学函数的双重版本外,C ++还以相同的语义添加了这些函数的float和long double重载版本。
这将是ambiguous
的int
情况,但该标准要求的是,提供足够的过载,使得整数参数被转换为加倍 。 它在第11段中涉及( 强调我的 ):
此外,应有足够的额外过载来确保:
- 如果对应于double参数的任何算术参数的类型为long double,则对应于double参数的所有算术参数都将有效地转换为long double。
- 否则,如果与double参数对应的任何算术参数具有double类型或整数类型, 则与double参数对应的所有算术参数都将有效地转换为double。
- 否则,所有与double参数相对应的算术参数都具有float类型。
更新资料
正如@nos指出的那样,被调用的sqrt
版本可能来自math.h
标头,而不是cmath
的重载,如果是这种情况,并且有可能在此处定义了实现 ,那么我们可能会恢复为旧如果唯一可用的版本是sqrt(double)
,则为C样式行为,这意味着int将隐式转换为double 。
我发现在gcc
和clang
对此进行测试的一种方法是将long类型用于a
,如果我们只有sqrt(double)
可用,它与-Wconversion
标志一起触发在我的平台上可能更改值的警告。 的确,如果我包括math.h
而不是cmath
我们可以产生此警告。 尽管我无法在clang中触发此行为,但这似乎表明这与实现有关 。
由于隐式转换 。 sqrt
是为double
定义的,并且可以将int
值隐式转换为double
类型的值。
(实际上很难阻止使用int
调用需要使用double
的函数。您可能会让编译器发出警告,但是由于这通常是一个保留值的转换,因此即使这样也可能很难。C ++从C继承了该设计以尽最大努力使代码工作,即使它需要扭曲。其他语言对此类型也要严格得多。
sqrt
被定义为double
。 C ++允许您将int
隐式转换为double
。
int n = 3;
double x = sqrt(n); // implicit conversion of n from int to double
当您将该值用作函数参数或将其分配给变量时,可能会发生隐式转换。
第二种情况的示例是:
int n = 3;
double x = n; // implicit conversion of n from int to double
注意,运算符也只是函数。 因此,您还可以在double
添加一个int
,从而在调用实际的加法之前将int
转换为double
:
int n = 3;
double x = 1.0;
double sum = n + x; // implicit conversion of n from int to double
因为存在从int
到double
的隐式转换。
进行转换后,您的代码将如下所示:
cout << "Square root of n == " << sqrt((double)n) << "\n";
因为编译器实际上是自动(即“隐式”)将整数转换为double
(或者可能是long double
)并将该值发送到sqrt()
。 这是完全正常和完全合法的。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.