我在 C中看到了以下代码行。
int mask = ~0;
我已经打印了mask
C 和 C++ 中的值。它总是打印-1
。
所以我确实有一些问题:
- 为什么
~0
要为掩码变量赋值? - 目的是
~0
什么? - 我们可以使用
-1
代替~0
吗?
这是一种可移植的方式,可以将整数中的所有二进制位设置为 1 位,而无需知道当前架构上的整数中有多少位。
C 和 C++ 允许 3 种不同的有符号整数格式:符号幅度、一个补码和二进制补码
~0
无论系统使用何种符号格式,都将产生全一位。所以它的便携性比-1
您可以添加U
后缀 (ie ) 以生成可移植-1U
的全一位模式1。但是表明意图更清楚:反转值 0 中的所有位,而 -1 将表明需要一个减一的值,而不是它的二进制表示~0
1因为无符号运算总是以比结果类型可以表示的最大值大一的数字为模减少
在 2 的补码平台上(假设)给你 -1,但规则禁止直接写 -1(只允许整数 0..255、一元!
和~
二进制&
、、、、和)。^
|
+
<<
>>
您正在研究一个编码挑战,该挑战对操作符和语言结构有许多限制,以执行给定的任务。
第一个问题是在不使用运算符的情况下返回值 -1-
。
在用二进制补码表示负数的机器上,该值-1
表示为所有位设置为1
,因此~0
计算结果为-1
:
/*
* minusOne - return a value of -1
* Legal ops: ! ~ & ^ | + << >>
* Max ops: 2
* Rating: 1
*/
int minusOne(void) {
// ~0 = 111...111 = -1
return ~0;
}
文件中的其他问题并不总是正确实施。第二个问题,返回一个布尔值,表示一个int
值适合 16 位有符号的事实short
有一个缺陷:
/*
* fitsShort - return 1 if x can be represented as a
* 16-bit, two's complement integer.
* Examples: fitsShort(33000) = 0, fitsShort(-32768) = 1
* Legal ops: ! ~ & ^ | + << >>
* Max ops: 8
* Rating: 1
*/
int fitsShort(int x) {
/*
* after left shift 16 and right shift 16, the left 16 of x is 00000..00 or 111...1111
* so after shift, if x remains the same, then it means that x can be represent as 16-bit
*/
return !(((x << 16) >> 16) ^ x);
}
左移负值或移位值超出范围的数字int
具有未定义的行为,右移负值是实现定义的,因此上述解决方案是不正确的(尽管它可能是预期的解决方案)。
很久以前,这就是您在极其有限的设备(例如 1K ZX 80 或 ZX 81 计算机)上节省内存的方式。在 BASIC 中,你会
Let X = NOT PI
而不是
LET X = 0
由于数字存储为 4 字节浮点数,因此后者比第一个 NOT PI 替代方案多占用 2 个字节,其中 NOT 和 PI 中的每个占用一个字节。
在所有计算机体系结构中都有多种编码数字的方法。当使用 2 的补码时,这总是正确的:~0 == -1
. 另一方面,一些计算机使用 1 的补码来编码负数,上面的例子是不正确的,因为~0 == -0
. 是的,1s 补码有负零,这就是为什么它不是很直观。
所以对于你的问题
mask & sth == sth
我个人的想法——让你的代码尽可能地独立于平台。成本相对较小,代码变得防故障