整数算术表达式中的提升

Promotion in integer arithmetic expressions

我有两个相关问题:

  1. 在比较形式为 x * y == z(或 x + y == z)的算术表达式时,标准怎么说,不同的编译器做了什么,其中 x * y 太大,x 或 y 都无法容纳,但不大于 z。

  2. 具有相同基础二进制值的等宽有符号整数和无符号整数之间的比较怎么样?

下面的例子可以阐明我的意思

#include <stdio.h>
#include <stdint.h>
#include <string.h>

int main (void)
{
    uint8_t x = 250;
    uint8_t y = 5;
    uint16_t z = x*y;
    uint8_t w = x*y;

    if (x * y == z)            // true
        puts ("x*y = z");
    if ((uint16_t)x * y == z)  // true
        puts ("(uint16_t)x*y = z");
    if (x * y == (uint8_t)z)   // false
        puts ("x*y = (uint8_t)z");
    if (x * y == w)            // false
        puts ("x*y = w");
    if ((uint8_t)(x * y) == w) // true
        puts ("(uint8_t)x*y = w");
    if (x * y == (uint16_t)w)  // false
        puts ("x*y = (uint16_t)w");

    int8_t X = x;
    if (x == X)                // false
        puts ("x = X");
    if (x == (uint8_t)X)       // true
        puts ("x = (uint8_t)X");
    if ((int8_t)x == X)        // true
        puts ("(int8_t)x = X");
    if (memcmp (&x, &X, 1) == 0) // true
        puts ("memcmp: x = X");
}

第一部分并不让我感到惊讶:如 Which variables should I typecast when doing math operations in C/C++? 中所述,编译器在算术运算期间隐式地将较短的整数提升为较长的整数(我想这适用于比较运算符)。这是保证的标准行为吗?

但是那个问题的答案以及 Signed/unsigned comparisons 的答案都说有符号整数应该提升为无符号整数。我原以为上面的 x == X 是正确的,因为它们拥有相同的数据(参见 memcmp)。相反,似乎发生的是两者都被提升为更宽的整数,然后发生有符号到无符号(反之亦然)。

编辑 2:

我特别感兴趣的情况是,如果出现错误,函数 returns int 将为 -1,否则将代表例如写入的字节数,应始终为正数。这种类型的标准函数returnssize_t,如果我没有记错的话在大多数平台上都是int64_t,但是写入的字节数可以一直到[=17] =].因此,如果我想将 returned intssize_t 与预期写入字节的无符号值进行比较,显式转换为 unsigned intsize_t(如果我没有弄错与 ssize_t 相同的宽度,但需要 unsigned)?


编辑 1:

我无法理解以下内容:

#include <stdio.h>
#include <stdint.h>

int main (void)
{
    int8_t ssi = UINT8_MAX;
    uint8_t ssu = ssi;
    printf ("ssi = %hhd\n", ssi); // -1
    printf ("ssu = %hhu\n", ssu); // 255
    if (ssi == ssu) // false
        puts ("ssi == ssu");

    puts ("");
    int16_t si = UINT16_MAX;
    uint16_t su = si;
    printf ("si = %hd\n", si); // -1
    printf ("su = %hu\n", su); // 65535
    if (si == su) // false
        puts ("si == su");

    puts ("");
    int32_t i = UINT32_MAX;
    uint32_t u = i;
    printf ("i = %d\n", i); // -1
    printf ("u = %u\n", u); // 4294967295
    if (i == u)   // true????
        puts ("i == u");

    puts ("");
    int64_t li = UINT64_MAX;
    uint64_t lu = li;
    printf ("li = %ld\n", li); // -1
    printf ("lu = %lu\n", lu); // 18446744073709551615
    if (li == lu) // true
        puts ("li == lu");
}

虽然 64 位示例可以解释为没有更宽的整数可供选择,但 32 位示例是违反直觉的。不应该和 8 位和 16 位的情况一样吗?

请注意,像 uint8_t x = 250; ... int8_t X = x; 这样的 comapre 之前的代码是实现定义的

  1. comparison between arithmetic expression of the form x * y == z (or x + y == z), where x * y is too large for either x or y to hold, but not larger than z.

计算 x * y 的乘积时不考虑 z。产品类型由 1) xy 都经历了 整数促销 intunsigned。 2)如果类型不同,则rank小的通过普通算术转换到大的,然后计算乘积。如果该产品在数字上溢出目标类型,则在有符号类型的情况下 未定义行为 和在无符号类型的情况下回绕。

产品计算完成后,比较会遵循与通常的整数提升相同的规则,然后是更高的排名。

  1. What about comparison between signed and unsigned integers of equal width with the same underlying binary value?

2 个参数,独立地经过整数提升。如果它们的符号不同,则将有符号的类型转换为匹配的无符号类型。然后比较这些值。

任何 2 个相同的二进制 values 将始终比较相同。 __integer promotions_ 之后,任何 2 个相同的二进制 位模式 (不包括稀有的填充位)宽度相同,将进行比较如果带符号的类型是普通 2 的补码,则相同。

int8_t i = -1;
uint8_t u = i;         // u =  255
if (i == u) --> false  // both i,x promoted to int and -1 != 255)

int i = -1;
unsigned u = i;        // u = UINT_MAX  
if (i == u) --> true   // i promoted to unsigned and value UINT_MAX