I want to play with overflow of signed short integer variable. I declare variable a1 as short, and then I give the greater positive value, zero is 'considered' positive, so maximum value of a signed integer (be it short, int, long or long long) must be exp2(8*sizeof(variable)-1)-1, mustn't it?
#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;
}
So I get a overflow-warning, as I wanted, that's the target of this code:
warning: overflow in implicit constant conversion [-Woverflow]
Then ./a.out and the output is
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.
The 2nd printf works fine, doesnt it? But the 1st I think should show the same value to printf of variable a1 (a1=exp2(8*sizeof(a1)-1)-1;) and to the casting of (short) exp2(8*sizeof(a1)-1)-1. I rewrite it more clear:
#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;
}
And the output is
It should be 32766 = 32767.
When I think it should be: "It should be 32767 = 32767."
Help me to understand it please
SOLVED by @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;
}
I must remark that brakets here are important, without them, I mean (short) round(exp2(CHAR_BIT*sizeof(a1)-1))-1
, you get another value.
double
to int
truncation.
The unposted non-standard function exp2()
is certainly double exp2(double x)
and not well implemented.
When converting small int
to double
as in passing the argument to exp2(8*sizeof(a1)-1
, the conversion is exact.
When taking the result and converting to short
as in short a1=exp2()
, that is the issue. Suppose the result of exp2(15)
slightly in error and was 32767.99999999 instead of the hoped for 32768.0. Then conversion to to int
is "truncation toward 0".
Often the solution is to round before truncation.
// add vvvvvv v
(short) round(exp2(CHAR_BIT*sizeof(a1)-1)) - 1
Try debugging with the following to see the return value with enough precision.
#include <float.h>
int short a1;
printf("%.*f\n", DBL_DECIMAL_DIG - 1, (double) exp2(CHAR_BIT*sizeof(a1)-1));