【问题标题】:C: uint16_t subtraction behavior in gccC: gcc 中的 uint16_t 减法行为
【发布时间】:2012-04-20 08:03:03
【问题描述】:

我正在尝试减去两个无符号整数并将结果与​​有符号整数(或文字)进行比较。使用 unsigned int 类型时,行为符合预期。当使用uint16_t(来自stdint.h)类型时,行为不是我所期望的。比较是使用 gcc 4.5 完成的。
给定以下代码:

unsigned int a;
unsigned int b;

a = 5;
b = 20;

printf("%u\n", (a-b) < 10);

输出为 0,这是我的预期。 a 和 b 都是无符号的,并且 b 大于 a,所以结果是一个大于 10 的大无符号数。现在如果我将 a 和 b 更改为 uint16_t:

uint16_t a;
uint16_t b;

a = 5;
b = 20;

printf("%u\n", (a-b) < 10);

输出为 1。这是为什么呢?两个 uint16_t 类型之间的减法结果是否存储在 gcc 的 int 中?如果我将10 更改为10U,则输出再次为 0,这似乎支持这一点(如果减法结果存储为 int 并且与 unsigned int 进行比较,则减法结果将转换为无符号整数)。

【问题讨论】:

  • 结果不仅仅是“存储在一个 int 中”。整个减法执行为int 减法,即两个uint16_t 操作数在减法甚至有机会之前都转换为int开始吧。阅读积分促销活动。

标签: c gcc unsigned stdint


【解决方案1】:

因为计算不是使用 int / unsigned int 以下的类型(char、short、unsigned short 等;但不是 long、unsigned long 等),但它们首先被提升为 int 或 unsigned int 之一。 “uint16_t”在您的实现中可能是“unsigned short”,在您的实现中提升为“int”。所以计算的结果是“-15”,小于 10。

在使用 16 位计算的旧实现中,“int”可能无法表示“unsigned short”的所有值,因为它们具有相同的位宽。这样的实现必须将“unsigned short”提升为“unsigned int”。在此类实现中,您的比较结果为“0”。

【讨论】:

    【解决方案2】:

    在执行-&lt; 操作之前,会应用一组称为常规算术转换 的转换来将操作数转换为通用类型。作为此过程的一部分,将应用整数提升,它将比intunsigned int 更窄的类型提升为这两种类型之一。

    在第一种情况下,ab 的类型是 unsigned int,因此由于 - 运算符而不会发生类型更改 - 结果是具有较大正值 @ 的 unsigned int 987654330@。然后,因为intunsigned int具有相同的rank,10类型为int的值被转换为unsigned int,然后进行比较得到值0

    在第二种情况下,很明显,在您的实现中,int 类型可以保存uint16_t 类型的所有值。这意味着当应用整数提升时,ab 的值将提升为类型 int。执行减法运算,得到类型为int 的值-15&lt; 的两个操作数都已经是 int,因此不执行任何转换; &lt; 的结果是 1

    在后一种情况下使用10U 时,a - b 的结果仍然是-15,类型为int。然而,现在,通常的算术转换导致该值被转换为unsigned int(就像第一个示例中的10),这导致值UINT_MAX - 14&lt; 的结果是 0

    【讨论】:

    • "很明显,在您的实现中,int 类型可以保存 uint16_t 类型的所有值"这是关键,但我很惊讶 gcc (Linux)在执行比较之前将unsigned short 升级到int(而不是unsigned)(在我的情况下这不是预期的结果)...... GNU 的人肯定有一个很好的这种选择的原因,但我认为拥有所有值 unsigned 然后与 negative 操作数进行比较可能会产生误导......也许应该只进行促销直到最大的类型(这里是 16 位)。
    • @e2-e4:这些提升规则是 C 标准的一部分,而不是编译器作者决定的。要记住的经验法则是,永远不会在比int / unsigned int 更窄的类型中进行算术运算,因此如果您正在处理更窄的无符号类型并想要控制完成算术运算的类型,请将操作数转换为unsigned int 明确。
    猜你喜欢
    • 1970-01-01
    • 2021-11-16
    • 1970-01-01
    • 2019-09-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多