int16_t和int8_t的Fixpoint-Overflow-Traps

skn*_*skn 7 c ubuntu gcc

我有一个复杂的定点运算程序.

似乎偶尔有溢出.

为了找到它们,我设置了旗帜-ftrapv.这似乎只适用于int32_t.那是对的吗?

有没有办法用int16_t和实现相同的行为int8_t

这是我的测试代码:

#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);
}
Run Code Online (Sandbox Code Playgroud)

我编译:

rm a.out; gcc -ftrapv main.c && ./a.out
Run Code Online (Sandbox Code Playgroud)

得到:

int8: -128
int16: -32768
Aborted
Run Code Online (Sandbox Code Playgroud)

我的编译器版本是gcc (Ubuntu 5.4.0-6ubuntu1~16.04.4) 5.4.0 20160609.

注意:有些答案是指我之前错误编写的测试程序.

Lun*_*din 6

我不知道你想做什么.

  • int8_t可以容纳的最大值是127而不是 255.
  • 最大值a int16_t是32767而不是 65535.
  • a int32_t可以容纳的最大值确实是2147483647.

所以这就是你的代码所做的:

  • int8_t int8 = 255;将值255分配给最多可容纳127的变量.它不适合,以某种实现定义的方式调用隐式转换.最有可能的是你得到的值为-1.这是一个隐式左值转换,没有有符号整数溢出.

  • printf("int8: %d\n",int8 + 1);打印结果-1 + 1.是的0.没有任何溢出.

  • 同样的事情发生在16位变量,隐式转换,最终值为-1,打印0.

  • int32_t int32 = 2147483647;此行与其他两行不同,因为您实际上将int32设置为它可以包含的最大值.如果你采取+1这种做法,你会得到一个有符号的整数溢出,它会调用未定义的行为.

最重要的是,两个较小的整数类型在添加时不会溢出,即使这是您的代码正在做的事情(它没有).两个操作数都会将整数提升为类型int- 不会有溢出.有关其工作原理的详细说明,请参阅隐式类型提升规则.


unw*_*ind 5

我不这么认为,因为C的默认整数提升规则,算法确实不会发生在较小的类型中.

例如(来自C11草案,§5.1.2.311):

示例2
在执行片段时

char c1, c2;
/* ... */
c1 = c1 + c2;
Run Code Online (Sandbox Code Playgroud)

"整数提升"要求抽象机器将每个变量的值提升为int大小,然后添加两个ints并截断总和.

这常常是代码混淆的原因,例如:

uint8_t x;

x = get_some_byte();
x |= 1;
Run Code Online (Sandbox Code Playgroud)

最后一行实际上相当于:

x = x | 1;
Run Code Online (Sandbox Code Playgroud)

并且右侧将被提升为int,因此分配"回到" uint8_t风险截断,一些工具警告你.