C -printf 铸造

C -printf casting

我想玩一下有符号短整型变量的溢出。我将变量 a1 声明为 short,然后我给出较大的正值,零是 'considered' 正数,因此有符号整数的最大值(短,整数,长或 long long) 必须是 exp2(8*sizeof(variable)-1)-1,不是吗?

#include<stdio.h>
#include <math.h>

int main()
{

int short a1=2;

a1=exp2(8*sizeof(a1)-1)-1;

printf("The last value that DOES NOT overflow in a integer as \'signed short\' (%i bytes) is %hi.\nIf I define this variable equal to this value I get the value in the variable %hi.\n",(unsigned char) sizeof(a1), (short) exp2(8*sizeof(a1)-1)-1, a1);/*key word short from "(short) exp2(8*sizeof(a1)-1)-1"*/

a1=exp2(8*sizeof(a1)-1);/*warning-overflow: "warning: overflow in implicit constant conversion [-Woverflow]"*/

printf("The 1st value that overflows in a integer as \'signed short\' (%i bytes) is %i.\nIf I define this variable equal to this value instead I get the value in the variable %i.\n",(unsigned char) sizeof(a1), (int) exp2(8*sizeof(a1)-1), a1);/*key word int from "(int) exp2(8*sizeof(a1)-1)"*/
return;
}

所以我得到了一个溢出警告,正如我想要的那样,这就是这段代码的目标:

warning: overflow in implicit constant conversion [-Woverflow]

然后./a.out,输出为

The last value that DOES NOT overflow in a integer as 'signed short' (2 bytes) is 32766. If I define this variable equal to this value I get the value in the variable 32767. The 1st value that overflows in a integer as 'signed short' (2 bytes) is 32768. If I define this variable equal to this value instead I get the value in the variable 32767.

第二个 printf 工作正常,不是吗?但是我认为第一个应该对变量 a1 (a1=exp2(8*sizeof(a1)-1)-1;) 的 printf 和 (short) exp2(8*sizeof(a1)- 1)-1。 我重写的更清楚:

#include<stdio.h>
#include <math.h>
#include <limits.h>

int main()
{
int short a1=exp2(CHAR_BIT*sizeof(a1)-1)-1;
printf("It should be %hi = %hi.\n",(short) exp2(CHAR_BIT*sizeof(a1)-1)-1, a1);
return;
}

输出为

It should be 32766 = 32767.

当我认为应该是:"It should be 32767 = 32767."

请帮我理解一下

@chux

已解决
#include<stdio.h>
#include <math.h>
#include <limits.h>
#include <float.h>


int main()
{
int short a1=exp2(CHAR_BIT*sizeof(a1)-1)-1;
printf("It should be %hi = %hi.\n",(short) (round(exp2(CHAR_BIT*sizeof(a1)-1))-1), a1);
return;
}

我必须指出这里的括号很重要,没有它们,我的意思是 (short) round(exp2(CHAR_BIT*sizeof(a1)-1))-1,你会得到另一个值。

doubleint 截断。

未发布的非标准函数 exp2() 当然是 double exp2(double x) 并且没有很好地实现。

当将小 int 转换为 double 时,就像将参数传递给 exp2(8*sizeof(a1)-1 一样,转换是准确的。

当获取结果并转换为 short 时,如 short a1=exp2() 就是问题所在。假设 exp2(15) 的结果略有错误,是 32767.99999999 而不是希望的 32768.0。然后转换为 int 是 "truncation toward 0".

通常解决方案是在截断前舍入

// add  vvvvvv                           v 
(short) round(exp2(CHAR_BIT*sizeof(a1)-1)) - 1

尝试使用以下方法进行调试,以足够精确地查看 return 值。

#include <float.h>
int short a1;
printf("%.*f\n", DBL_DECIMAL_DIG - 1, (double) exp2(CHAR_BIT*sizeof(a1)-1));