1
votes

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.

1
Prefer CHAR_BIT rather than 8 ... don't forget to #include <limits.h>pmg
Overflow of a signed integer is undefined behavior. See en.cppreference.com/w/cpp/language/operator_arithmetic.Lingxi
I did as you suggested, thx btw, and I get the same resaults: inline #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; }daniel
you overflow it, and as it's an undefined behaviour, the compiler throws a warning... There is no error or problem here. If you don't want the warning use bitwise operation instead of exp2: a1=1<<((8*sizeof(a1)-1));yakoudbz
@yakoudbz shifting into the sign bit is also undefined behavior (since shifting left is defined in terms of multiplying by the appropriate power of two).The Paramagnetic Croissant

1 Answers

2
votes

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));