英文:
Implicit conversion to double in C
问题
我正在尝试理解C语言中的隐式转换。我有以下C代码:
#include <stdio.h>
#include <stdlib.h>
int main() {
int a = -6;
size_t b = 100;
int result = a * b; /* a is converted to size_t,
multiply two unsigned ints and cast the result to int
*/
double dresult = a * b;
printf("Result : %d \n", result); // Output Result : -600
printf("Double Result : %f \n", dresult); // Output Double Result : 18446744073709551616.000000
return 0;
}
根据我从cppreference了解到的,result
应该是一些垃圾值(当转换为double时打印出来),但为什么它给我正确的值?
英文:
I am trying to understand implicit conversion in C .I have the following C code:
#include <stdio.h>
#include <stdlib.h>
int main() {
int a = -6 ;
size_t b = 100 ;
int result = a*b ; /* a is converted to size_t,
multiply two unsigned ints and cast the result to int
*/
double dresult = a*b ;
printf("Result : %d \n",result); // Output Result : -600
printf("Double Result : %f \n",dresult); // Output Double Result : 18446744073709551616.000000
return 0;
}
From what I understood from cppreference, the result
should be some garbage (as printed when converted to double) value, but why does it give me the right value?
答案1
得分: 4
当评估表达式 a*b
时,将应用通常的算术转换于两个操作数。这意味着:
-
在
size_t
具有等于或高于int
的等级的平台上(这在大多数平台上是成立的),a
将被转换为size_t
。由于size_t
是无符号的,a
的值(即-6
)将被转换为无符号值。在size_t
为64位的平台上,这个值将是18446744073709551610
。将这个值与b
的值(即100
)相乘将产生数学结果1844674407370955161000
,这在64位的size_t
中是不能表示的。因此,假设64位的size_t
,实际结果将是数学结果对18446744073709551616
(2的64次方)取模的值,即18446744073709551016
。在size_t
为32位的平台上,相应的结果是4294966696
。请注意,这种"溢出"不会引发未定义行为,因为只有有符号整数溢出会引发未定义行为。无符号整数溢出是被明确定义的。 -
在
size_t
等级低于int
的平台上(这在理论上是可能的,也被ISO C标准允许,但实际上不太可能存在),a
将不会被转换为size_t
,所以结果将简单地是-600
。
基于上述原因,根据您使用的平台不同,a*b
的结果可能是18446744073709551016
、4294966696
或-600
。
这行代码:
double dresult = a*b;
因此,将在dresult
中写入值18446744073709551016.0
、4294966696.0
或-600.0
,具体取决于您使用的平台。在您的平台上,由于浮点不精确性,数值18446744073709551016.0
似乎无法精确表示,因此它将四舍五入为18446744073709551616.0
。
使用以下代码:
int result = a*b;
情况就没有那么简单了。在a*b
评估为-600
的平台上,很明显值-600
将被写入result
。然而,在a*b
评估为18446744073709551016
的平台上,问题在于这个值在int
中是无法表示的,假设int
是32位的。在这种情况下,根据ISO C11标准的§6.3.1.3 §3,写入result
的值是实现定义的,或者会引发一个实现定义的信号。然而,在大多数平台上,结果实际上是通过反复减去目标类型的无符号版本中可表示的最大数值,加上一,直到结果在类型可表示的范围内获得的值。因此,结果将是18446744073709551016 - 18446744073709551616
,即-600
。这似乎也是您的平台的行为方式。
英文:
When evaluating the expression a*b
, the usual arithmetic conversions are applied to both operands. This means that
-
on platforms on which
size_t
has equal or higher rank thanint
(which is the case on most platforms),a
is converted tosize_t
. Sincesize_t
is unsigned, the value ofa
(which is-6
) will be converted to an unsigned value. On platforms on whichsize_t
is 64-bit, this value will be18446744073709551610
. Multiplying this value ofa
with the value ofb
(which is100
) will yield the mathematical result1844674407370955161000
, which is not representable in a 64-bitsize_t
. Therefore, assuming a 64-bitsize_t
, the actual result will be the mathematical result modulo18446744073709551616
(2 to the power 64), which is18446744073709551016
. On platforms on whichsize_t
is 32-bit, the corresponding result is4294966696
. Note that this "overflow" will not invoke undefined behavior, because only signed integer overflow will invoke undefined behavior. Unsigned integer overflow is well-defined. -
on platforms on which
size_t
has a rank less thanint
(which are theoretically possible and permitted by the ISO C standard, but unlikely to exist in practice),a
will not be converted tosize_t
, so the result will be simply-600
.
For the reasons stated above, depending on which platform you are using, the result of a*b
will likely be either 18446744073709551016
, 4294966696
or -600
.
The line
double dresult = a*b ;
will therefore likely write either the value 18446744073709551016.0
, 4294966696.0
or -600.0
to dresult
, depending on which platform you are using. On your platform, the number 18446744073709551016.0
does not seem to be exactly representable in a double
due to floating-point inaccuracy, so that it gets rounded to 18446744073709551616.0
.
With the line
int result = a*b ;
the situation is not quite as simple. On platforms on which a*b
evaluates to -600
, it is clear that the value -600
will be written to result
. However, on platforms on which a*b
evaluates to 18446744073709551016
, the problem is that this value is not representable in an int
, assuming that an int
is 32-bit. In that case, according to §6.3.1.3 ¶3 of the ISO C11 standard, the value written to result
is implementation-defined or an implementation-defined signal is raised. However, on most platforms, the result is simply the value that is obtained by repeatedly subtracting the maximum number representable in the unsigned version of the target type, plus one, until the result is in the range representable by the type. Therefore, the result would be 18446744073709551016 - 18446744073709551616
, which is -600
. This appears to also be how your platform is behaving.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论