I have a complicated program with fixed-point arithmetic.
It seems that there are occasional overflows.
To find them I have set the flag -ftrapv
. This seems to work only with int32_t
. Is that correct?
Is there a way to achieve the same behavior with int16_t
and int8_t
?
Here is my test code:
#include <stdio.h>
#include <stdint.h>
int main(void)
{
int8_t int8 = 127;
int8 += 1;
printf("int8: %d\n",int8);
int16_t int16 = 32767;
int16 += 1;
printf("int16: %d\n",int16);
int32_t int32 = 2147483647;
int32 += 1;
printf("int32: %d\n",int32);
}
I compile with:
rm a.out; gcc -ftrapv main.c && ./a.out
and get:
int8: -128
int16: -32768
Aborted
My compiler version is gcc (Ubuntu 5.4.0-6ubuntu1~16.04.4) 5.4.0 20160609
.
Note: Some of the answers refer to a test program that I have incorrectly written before.
I have no idea what you are trying to do.
int8_t
can hold is 127 and not 255. int16_t
is 32767 and not 65535. int32_t
can hold is indeed 2147483647. So this is what your code does:
int8_t int8 = 255;
Assign the value 255 to a variable that can hold a maximum of 127. It won't fit, invoke implicit conversion in some implementation-defined manner. Most likely you end up with the value -1. This is an implicit lvalue conversion and no signed integer overflow.
printf("int8: %d\\n",int8 + 1);
Print the result of -1 + 1
. It is 0
. No overflow anywhere.
The very same thing happens with the 16 bit variable, implicit conversion, end up with value -1, print a 0.
int32_t int32 = 2147483647;
This line is different from the other two, as you actually set the int32 to the maximum value it can contain. If you take +1
on that, you do get a signed integer overflow which invokes undefined behavior.
On top of that, the two smaller integer types can't overflow upon the addition, even if that was what your code was doing (which it doesn't). Both operands would get integer promoted to type int
- there would be no overflow. See Implicit type promotion rules for a detailed explanation about how this works.
I don't think so, since because of C's default integer promotion rules, the arithmetic really doesn't happen as the smaller types.
For instance (from the C11 draft, §5.1.2.3 11):
EXAMPLE 2
In executing the fragmentchar c1, c2; /* ... */ c1 = c1 + c2;
the "integer promotions" require that the abstract machine promote the value of each variable to
int
size and then add the twoint
s and truncate the sum.
This is frequently the cause of confusion in code like:
uint8_t x;
x = get_some_byte();
x |= 1;
The last line is really the equivalent of:
x = x | 1;
and the right-hand side will be promoted to int
, so the assignment "back" to uint8_t
risks truncating which some tools warn you about.
I have found the following minimally invasive method for myself:
#include <stdio.h>
#include <stdint.h>
#ifdef INTOF_CHECK
#define INTOF_ERROR (printf("line %d: loss of bits\n", __LINE__) & 0)
#define i8(v) ((v) > 127 || (v) < -127 ? INTOF_ERROR : (v))
#define i16(v) ((v) > 32767 || (v) < -32768 ? INTOF_ERROR : (v))
#else
#define i8(v) (v)
#define i16(v) (v)
#endif
int main(void)
{
int8_t int8 = i8(127);
printf("int8: %d\n",i8(int8 + 1));
int16_t int16 = i16(32767);
printf("int16: %d\n",i16(int16 + 1));
}
Compile with:
rm -f a.out; gcc main.c -DINTOF_CHECK && ./a.out
The output is:
line 16: loss of bits
int8: 0
line 19: loss of bits
int16: 0
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.