C中int类型的sqrt()函数

5

我正在Mac OS X上使用C语言进行编程。我正在使用math.h中的sqrt函数,用法如下:

int start = Data -> start_number;
double localSum;

for (start; start <= end; start++) {
    localSum += sqrt(start);
}

这个代码可以运行,但是为什么呢?为什么我没有收到警告?在sqrt的手册页面中,它接受一个double类型的参数,但是我却给了一个int类型的参数——它怎么能够工作呢?谢谢。
4个回答

11

不会导致精度损失的类型转换可能不会引发警告,它们会被隐式地转换。

int --> double //no loss in precision (e.g 3 became 3.00)
double --> int //loss in precision (e.g. 3.01222 became 3)

触发警告的条件和不触发的条件很大程度上取决于编译器和提供给它的标志,然而,大多数编译器(至少我使用过的那些)并不认为隐式类型转换足够“危险”以引起警告,因为这是语言规范中的一项特性。


是否警告:

C99 Rationale将其作为一个“指导方针”。

研究(隐式强制类型转换)问题的一个重要结果是认识到高质量的编译器可能做得很好,去寻找这种可疑的代码并提供(可选的)诊断,以及认真的讲师可能会对程序员进行隐式类型转换问题的警告。

C99 Rationale (Apr 2003) : 第45页


“因为它没有列出int转double的转换”,事实上,例如在C99的6.3.1条款中确实有此规定。我不知道eli-project是什么,但要么您误解了其含义,要么它还不是C标准的准确形式化表达。 - Pascal Cuoq
我想那是C89,被称为ANSI C。 - Anirudh Ramanathan
@PascalCuoq,这些只是说隐式转换发生了。实际上允许隐式的转换似乎没有被提到。谢谢 :) - Anirudh Ramanathan
1
6.3.1.4:2 当整数类型的值转换为实浮点类型时,如果要转换的值可以在新类型中精确表示,则它不变。如果要转换的值在可表示但无法精确表示的值范围内,则结果是最接近的更高或更低的可表示值,以实现定义的方式选择。如果要转换的值超出了可表示的值范围,则行为是未定义的。 - Pascal Cuoq
1
如果你对这种事情感兴趣,关于C11的最新和准确的正式化可以看 http://code.google.com/p/c-semantics/ 。我还没有阅读过它,但我使用了从其规则中派生的解释器。 - Pascal Cuoq
显示剩余6条评论

3
编译器知道sqrt的原型,因此它可以 - 也会 - 在调用函数之前生成将int参数转换为double所需的代码。
同样,如果您将double传递给具有已知原型的接受int参数的函数,则情况也是如此,编译器将生成所需的转换代码。
编译器是否警告此类转换取决于编译器和您在命令行上请求的警告级别。
对于int -> double的转换(通常使用32位(或16位)int和以IEEE754格式表示的64位doubles),如果可能的话,很难获得该转换的警告。
对于double -> int的转换,在gcc和clang中,您需要使用-Wconversion专门要求此类警告,否则它们将默默地编译代码。

1

Int可以安全地自动转换为double,因为没有数据丢失的风险。反之则不成立。要将double转换为int,必须明确地进行强制类型转换。


1
int foo = 42.3; 不需要强制转换。(在 C 中很多时候强制转换是错误的) - pmg

0

C语言编译器会自动将double和int进行一些类型转换。你也可以尝试以下方法:

int start = Data -> start_number;
int localSum;

for (start; start <= end; start++) {
   localSum += sqrt(start);
}

即使 localSum 是一个整数,这个方法也可以正常工作,但是它会将小数点后面的部分直接舍去。
例如,如果 sqrt() 返回值为 1.365,那么它将被存储为简单的 1。

我说的是“可能”,而不是“应该”。这只是演示隐式转换的效果。 - Strike

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接