我正在try 理解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应该是一些垃圾值(转换为双精度值时打印),但为什么它给了我正确的值?

推荐答案

当对表达式a*b求值时,usual arithmetic conversions被应用于两个操作数.这意味着

  • size_t的排名高于int的平台上(这是大多数64位平台),a被转换为size_t.由于size_t是无符号的,因此值a(即-6)将被转换为无符号的值.在size_t为64位的平台上,此值将为18446744073709551610.将该值a与值b(即100)相乘将得到数学结果1844674407370955161000,该结果不能用64位size_t表示.因此,假设64位size_t,实际结果将是以18446744073709551616为模(2的64次方)的数学结果,即18446744073709551016.请注意,此"溢出"不会调用未定义的行为,因为只有带符号的整数溢出才会调用未定义的行为.无符号整数溢出是明确定义的.

  • size_t的平台上,排名等于或小于int,a不会转换为size_t,因此结果将简单地为-600.

基于上述原因,根据您使用的平台,a*b的结果将是18446744073709551016-600.

这条线

double dresult = a*b ;

因此,将写入值1844674407370955-600.06.0-600.0dresult,具体取决于您使用的平台.

带着这条线

int result = a*b ;

情况并不是那么简单.在a*b计算结果为-600的平台上,很明显,值-600将写入result.然而,在a*b计算为18446744073709551016的平台上,根据§6.3.1.3 ¶3 of the ISO C11 standard,写入result的值是实现定义的,或者引发实现定义的信号.然而,在大多数平台上,结果只是通过重复减go 目标类型的无符号版本中可表示的最大数字加1而获得的值,直到结果在该类型可表示的范围内为止.因此,结果将是18446744073709551016 - 18446744073709551616,即-600.这似乎也是你的平台的表现.

C++相关问答推荐

C中的整字母后缀i是什么

如何启用ss(另一个调查套接字的实用程序)来查看Linux主机上加入的多播组IP地址?

在struct中调用函数,但struct在void中 *

如何创建由符号组成的垂直结果图形?

自定义应用程序上的日志(log)轮换问题

将指针作为参数传递给函数

ATmega328P EEPROM未写入

为什么即使在强制转换时,此代码也会溢出?

为什么STM32G474RE上没有启用RCC PLL

C中的指针增量和减量(*--*++p)

C++中矢量类型定义和数据保护的高效解决方案

为什么该函数不将参数值保存到数据 struct 中?

如何捕捉只有换行符或空格字符缓冲区的边缘大小写

C代码在字符串中删除不区分大小写的子字符串的问题

Zlib:解压缩大文件导致";无效代码长度设置";错误

不确定如何处理此编译错误

int * 指向int的哪个字节?

隐藏测试用例无法在c程序中计算位数.

当读取可能会阻塞管道中的父进程时,为什么要等待子进程?

std::malloc/calloc/realloc/free 与纯 C 的 malloc/calloc/realloc/free 有什么不同