我有两个相关的问题:
当涉及x * y == z(或x + y == z)形式的算术表达式之间的比较时,标准说什么,以及不同的编译器做了什么,其中x * y对于x或y来说太大而不能保持,但不大于z。
如何比较具有相同基础二进制值的等宽的有符号和无符号整数?
下面的例子可以澄清我的意思
#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
)。似乎发生的事情是,两者都被提升为更宽的整数,然后签名到无符号(或反之亦然)发生。
特别是我感兴趣的是一个函数返回int
的情况,如果出现错误将为-1,否则将表示例如写入的字节数,应始终为正数。此类型的标准函数返回ssize_t
,如果我在大多数平台上没有弄错,则与int64_t
相同,但写入的字节数可以一直到UINT64_MAX
。因此,如果我想将返回的int
或ssize_t
与写入的预期字节的无符号值进行比较,则显式转换为unsigned int
或size_t
(如果我没有记错的话)需要与ssize_t
相同的宽度但是无符号)?
我无法理解以下内容:
#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位情况相同吗?
答案 0 :(得分:3)
请注意,像[{1}}这样的comapre的先前代码是实现定义@David Bowling
- 形式x * y == z(或x + y == z)的算术表达式之间的比较,其中x * y对于x或y来说太大而不能保持,但不大于z。
醇>
计算uint8_t x = 250; ... int8_t X = x;
的乘积而不考虑x * y
。产品的类型由以下各项确定:1)z
和x
通过整数促销到y
或int
。 2)如果类型不同,较小的 rank 中的一个通过通常的算术转换到较高的那个,然后计算产品。如果该产品在数字上溢出目标类型,则在签名类型的情况下未定义行为,在无符号类型的情况下为环绕。
在计算产品后,比较符合通常的整数促销的相同规则,然后是更高的等级。
- 如何比较具有相同基础二进制值的等宽的有符号和无符号整数?
醇>
2个参数,独立完成整数提升。如果它们的符号不同,则签名的那个将转换为匹配的无符号类型。然后比较这些值。
任何2个相同的二进制值将始终进行比较。 __integer promotion_之后,如果有符号类型是常见的2的补码,任何2个相同宽度的二进制位模式(不计算稀有填充位)将相同
unsigned