CSAPP:如果我想将一个 8 位数字向左移动 8 个位置会发生什么
CSAPP: What should happen if I want to shift an 8-bit number 8 positions to the left
这个问题来自CSAPP CMU ICS 2015Fall Lecture 02 Bits, Bytes, and Integers 19:30,相关脚本是
The other thing is confusing to people is
What should happen if you say I want to shift an 8-bit number 8 positions to the left
And x is a single byte what do you think you should get
Zero that would be a pretty logical thing you kind of shift all those bits out you fill them with zeros
----------- I don't understand -----------
On most machines you'll get whatever x was
Because what will do is it will compute this number mod 8
And the reason that happens is if you think about it
It's looking at just the lower two three bits of the shift amount and ignoring all the rest
So that's effectively like module 8
So that's just a warning and some machines it does
What you just thought it should and other machines it does this
And so there's no no guarantee and in C that it will be one way or the other
Randal E. Bryant 说将 8 位数字向左移动 8 个位置时有两个结果。 (如果我错了请纠正我)
- 零
mod规则 8 不变
我用横线把不懂的部分隔开。特别是 在大多数机器上你会得到任何 x 是 和 因为它会计算这个数字 mod 8, 我不明白为什么x和x一样mod 8.
谁能对水平线下方的部分进行更多解释,最好使用可运行的程序?
SO 上有一些相关问题,例如 and ,但都没有包含 module 部分。
将一个8位字节左移8个位置可以用不同的方式分析:
- 在算术上,将一个值向左移动 8 个位置就是乘以 256,它产生一个低 8 位全为零的数字,因此当存储回一个 8 位字节时,你得到
0
.
- 硬件移位指令通常只将内存字移位小于其宽度的位数。在很多架构上,比如intel,这个移位量数是通过屏蔽移位值的高位得到的。因此,将一个字节向左移动 8 个位置的指令有效地将 8 位寄存器或内存参数中的值移动
8 & 7
个位置,即移动 0 位,保持值不变。
- 为了适应硬件限制,C 语言未定义将整数移动大于或等于其宽度的多个位置。这适用于 整数提升 之后,因此它不适用于 8 位字节(例如存储在
uint8_t
中),因为这些值首先提升为类型 int
,它至少有 15 个值位。
所以在C语言中,将一个字节移动8个位置就是将它的值乘以256,在16位整数的体系结构上最终可能会超出int
类型的范围
让我们来分析一下这段看似无辜的代码:
uint8_t shift8(uint_8 b) {
return b << 8;
}
因为b
首先提升为int
,保留其值。此值乘以 256,可能会超出 int
的范围,从而导致未定义的行为。在 int
大于 16 位的体系结构上,该值然后被隐式转换为 return 类型 uint8_t
,它完全定义并计算为模 256 的值,当然是 0。
所以上面的函数是一致的,并且在许多系统上总是 returns 0,但它并不完全一致,并且在具有 16 位整数的体系结构上具有未定义的行为。
这个问题来自CSAPP CMU ICS 2015Fall Lecture 02 Bits, Bytes, and Integers 19:30,相关脚本是
The other thing is confusing to people is
What should happen if you say I want to shift an 8-bit number 8 positions to the left
And x is a single byte what do you think you should get
Zero that would be a pretty logical thing you kind of shift all those bits out you fill them with zeros
----------- I don't understand -----------
On most machines you'll get whatever x was
Because what will do is it will compute this number mod 8
And the reason that happens is if you think about it
It's looking at just the lower two three bits of the shift amount and ignoring all the rest
So that's effectively like module 8
So that's just a warning and some machines it does
What you just thought it should and other machines it does this
And so there's no no guarantee and in C that it will be one way or the other
Randal E. Bryant 说将 8 位数字向左移动 8 个位置时有两个结果。 (如果我错了请纠正我)
- 零
mod规则 8不变
我用横线把不懂的部分隔开。特别是 在大多数机器上你会得到任何 x 是 和 因为它会计算这个数字 mod 8, 我不明白为什么x和x一样mod 8.
谁能对水平线下方的部分进行更多解释,最好使用可运行的程序?
SO 上有一些相关问题,例如
将一个8位字节左移8个位置可以用不同的方式分析:
- 在算术上,将一个值向左移动 8 个位置就是乘以 256,它产生一个低 8 位全为零的数字,因此当存储回一个 8 位字节时,你得到
0
. - 硬件移位指令通常只将内存字移位小于其宽度的位数。在很多架构上,比如intel,这个移位量数是通过屏蔽移位值的高位得到的。因此,将一个字节向左移动 8 个位置的指令有效地将 8 位寄存器或内存参数中的值移动
8 & 7
个位置,即移动 0 位,保持值不变。 - 为了适应硬件限制,C 语言未定义将整数移动大于或等于其宽度的多个位置。这适用于 整数提升 之后,因此它不适用于 8 位字节(例如存储在
uint8_t
中),因为这些值首先提升为类型int
,它至少有 15 个值位。
所以在C语言中,将一个字节移动8个位置就是将它的值乘以256,在16位整数的体系结构上最终可能会超出int
类型的范围
让我们来分析一下这段看似无辜的代码:
uint8_t shift8(uint_8 b) {
return b << 8;
}
因为b
首先提升为int
,保留其值。此值乘以 256,可能会超出 int
的范围,从而导致未定义的行为。在 int
大于 16 位的体系结构上,该值然后被隐式转换为 return 类型 uint8_t
,它完全定义并计算为模 256 的值,当然是 0。
所以上面的函数是一致的,并且在许多系统上总是 returns 0,但它并不完全一致,并且在具有 16 位整数的体系结构上具有未定义的行为。