【问题标题】:Fixpoint-Overflow-Traps for int16_t and int8_tint16_t 和 int8_t 的定点溢出陷阱
【发布时间】:2017-09-12 08:52:45
【问题描述】:

我有一个复杂的定点算术程序。

似乎偶尔会出现溢出。

为了找到它们,我设置了标志-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);
}

我编译:

rm a.out; gcc -ftrapv main.c && ./a.out

然后得到:

int8: -128
int16: -32768
Aborted

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

注意:有些答案是指我之前写错的一个测试程序。

【问题讨论】:

  • 我不认为你的结果是正确的,因为小于 int 的类型总是会被提升为 int,所以那些 int8 和 int16 的操作不会溢出
  • @Lưu Vĩnh Phúc:是的,另见 Lundin 的回答
  • 投票结束,因为问题已经改变,现在发布的答案无效。

标签: c ubuntu gcc


【解决方案1】:

我不知道你想做什么。

  • int8_t 可以容纳的最大值是 127,不是 255。
  • int16_t 的最大值为 32767,不是 65535。
  • 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 的整数 - 不会溢出。有关其工作原理的详细说明,请参阅 Implicit type promotion rules。

【讨论】:

  • 你是对的!这是一个神器。我从 uint8_t 和 uint16_t 开始。
  • 输出大于 128, 32768, Aborted
【解决方案2】:

我不这么认为,因为由于 C 的默认整数提升规则,算术确实不会作为较小的类型发生。

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

示例 2
在执行片段时

char c1, c2;
/* ... */
c1 = c1 + c2;

“整数提升”要求抽象机提升 每个变量的值到int 大小,然后添加两个ints 和 截断总和。

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

uint8_t x;

x = get_some_byte();
x |= 1;

最后一行真的相当于:

x = x | 1;

并且右侧将被提升为int,因此“返回”到uint8_t 的赋值可能会被截断,某些工具会警告您。

【讨论】:

  • 即使没有隐式提升操作数,也不会有溢出,因为-1 + 1 是明确定义的。问题不在于隐式提升,而在于 OP 为变量分配了错误的值。
【解决方案3】:

我为自己找到了以下微创方法:

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

编译:

rm -f a.out; gcc main.c -DINTOF_CHECK && ./a.out

输出是:

line 16: loss of bits
int8: 0
line 19: loss of bits
int16: 0

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-05-30
    • 2011-10-16
    • 2015-09-22
    • 2012-02-22
    • 2010-10-03
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多