在Jens Gustedt的《现代C》一书中,第59页,他解释了如何使用无符号整数来模拟有符号整数. 他的示例代码显示了如何实现将两个重新解释为有符号整数的无符号整数进行比较:

bool is_negative(unsigned a) { 
   unsigned const int_max = UINT_MAX /2;
   return a > int_max;
}

bool is_signed_less(unsigned a, unsigned b) {
   if (is_negative(b) && !is_negative(a)) return false;
   else return a < b; 
} 

是我误解了什么,还是他错过了第二个特例,is_negative(a) = trueis_negative(b) = false

例如,如果我们想要a = -1b = 1,那么,使用2的补码,我们可以将它们表示为

unsigned int a = UINT_MAX; 
unsigned int b = 1;    

(例如,对于4位整数,我们将具有a=1111和b=0001). 现在我们有is_negative(a)个返回true,is_negative(b)个返回false.当调用is_signed_less(a, b)时,我们以else子句结束,而a < b(现在解释为无符号整数)将返回FALSE.但是,-1&lt;1显然是真的,因此该函数返回错误的结果.

这是本书的代码中的一个错字,还是有什么我不明白的地方?

推荐答案

这就是当人们试图变得"聪明"而不是遵循"保持简单,愚蠢"的最佳实践时所发生的事情.好的工程需要尽可能地编写simple个代码,例如:

bool is_signed_less_correct (unsigned a, unsigned b) {
  bool is_neg_a = is_negative(a);
  bool is_neg_b = is_negative(b);

  if(is_neg_a != is_neg_b) // one is negative
  {
    return is_neg_a; // if one is negative and it is a, return true otherwise false
  } 

  // both are negative or both are positive
  return a < b;
}

即使这段代码也有点太"聪明"了,因为它隐含地使用了-1==0xFFFF...是最大的2‘S补码符号数,因此无论它们是负的还是非负的,只要它们都是相同的符号,a < b都成立.

当然,您总是要编写一个小单元测试来判断它的健全性:https://godbolt.org/z/h4nKsffqr

输出:

-2 < -1 ? true  (is_signed_less_gustedt)
-1 < -1 ? false (is_signed_less_gustedt)
-1 <  0 ? false (is_signed_less_gustedt)
 0 < -1 ? false (is_signed_less_gustedt)
 0 <  1 ? true  (is_signed_less_gustedt)
 1 <  0 ? false (is_signed_less_gustedt)
 1 <  1 ? false (is_signed_less_gustedt)

-2 < -1 ? true  (is_signed_less_correct)
-1 < -1 ? false (is_signed_less_correct)
-1 <  0 ? true  (is_signed_less_correct)
 0 < -1 ? false (is_signed_less_correct)
 0 <  1 ? true  (is_signed_less_correct)
 1 <  0 ? false (is_signed_less_correct)
 1 <  1 ? false (is_signed_less_correct)

C++相关问答推荐

为什么我得到更多的256假阳性在PKZIP解密密钥验证?

当打印字符串时,为什么在c中没有使用常量限定符时我会收到警告?

为什么在Linux(特别是Ubuntu 20.04LTS)上,POSIX共享内存对象在重启后仍然存在,然后突然变成了根用户?

两个连续的语句是否按顺序排列?

我可以在C中声明不同长度数组的数组而不带变量名吗?

错误:包含文件时类型名称未知

如何在下面的C代码中正确管理内存?

为什么未初始化的 struct 的数组从另一个数组获取值?

当b是无符号字符时,int a=(b<;<;2)>;>;2;和int a=b&;0x3F;之间有什么区别?

获取前2个连续1比特的索引的有效方法

c程序,让用户输入两类数字,并给出输出用户输入多少个数字

C中的char**v*char[]

Linux/C:带有子进程的进程在添加waitid后都挂起

OMP并行嵌套循环

区分MySQL C界面中的文本和BLOB字段

如何使用 VLA 语法使用 const 指针声明函数

C Makefile - 如何避免重复提及文件名

(GNU+Linux) 多个线程同时调用malloc()

UEFI 应用程序中的计时器回调仅在 AMI BIOS 中挂起

初始化动态分配的布尔二维数组的最佳方法是什么?