位运算、大小端和位移操作,三者之间有何关联?

2026-05-17 11:071阅读0评论SEO问题
  • 内容介绍
  • 文章标签
  • 相关推荐

本文共计1264个文字,预计阅读时间需要6分钟。

一文高清字序程序和bit序+大小端的概念大家都很熟悉。这个概念主要针对32bit或64bit机器,多个字节的排序+输出顺序。这个词组非常奇特,了解了输出顺序。The Computer Science term Big-End

一文高清字节序和bit 序

大小端的概念大家都很熟悉了。

这个概念主要是针对 32bit或者 64bit机器中,多个字节的排列顺序

出处

这个词很奇怪,查了下出处。

The Computer Science terms Big-Endian and Little-Endian were introduced by Danny Cohen2in 1980. The key termendianhas its roots in the novel Gulliver’s Travels3by Jonathan Swift4where within a war occurs between two factions who are fighting over which end of a boiled egg should be opened for eating. The big end or the little end. Unsurprisingly, the same said book was the inspiration for the naming of theGulliverlibrary.

可以看到原出处是一个小说,里面描述两股势力因为 吃水煮蛋应该从鸡蛋的哪一端开始吃而发生了战争。类似于咸甜豆腐脑的争端。

Endianness就是指鸡蛋的两头。作者起这个名字,我猜是想代表字节序本质上是一个没有什么实质意义,却又真实存在的分歧。

具体区别

一图流:

个人觉得小端相对来说比较符合直觉:

高位在高地址,低位在低地址。

引发的问题

主要是在32位(或者64位)的机器上,如何解释 2字节或者单字节的数据。

以及一些强制类型转换可能出现的问题

bitwise endianness bit内部的大小端

上面讨论的是,64位机器内部,8个字节的顺序问题

实际上,对于一个字节内部的Bit,也存在一个对称的问题,bit的排列顺序是怎么样的

给定一个结构体:

struct Byte { UINT8 bit0:1; UINT8 bit1:1; UINT8 bit2:1; UINT8 bit3:1; UINT8 bit4:1; UINT8 bit5:1; UINT8 bit6:1; UINT8 bit7:1; };

 问题来了, bit 0 到底是在 Byte的 LSB还是在MSB?换个问的方法,我要修改bit 0, 是 byte |= (1 << 0), 还是byte |= (1 << 7)

简而言之的结论:

不确定。

C99 §6.7.2.1, paragraph 10 says:

"The order of allocation of bit-fields within a unit (high-order to low-order or low-order to high-order) is implementation-defined."

C99标准表示: 具体的bit order和compiler的实现相关。

所以用bit 来表示数据的方式,兼容性需要提个醒。

最安全的方式使用结构体内的成员引用方式。

如果需要显式的表示这些位置,最好用下面的定义方式:

1 /* Each of these preprocessor directives defines a single bit, 2 corresponding to one button on the controller. 3 Button order matches that of the Nintendo Entertainment System. */ 4 #define KEY_RIGHT 0b00000001 5 #define KEY_LEFT 0b00000010 6 #define KEY_DOWN 0b00000100 7 #define KEY_UP 0b00001000 8 #define KEY_START 0b00010000 9 #define KEY_SELECT 0b00100000 10 #define KEY_B 0b01000000 11 #define KEY_A 0b10000000 12 13 int gameControllerStatus = 0; 14 15 /* Sets the gameControllerStatus using OR */ 16 void KeyPressed( int key ) { gameControllerStatus |= key; } 17 18 /* Clears the gameControllerStatus using AND and ~ (binary NOT)*/ 19 void KeyReleased( int key ) { gameControllerStatus &= ~key; } 20 21 /* Tests whether a bit is set using AND */ 22 int IsPressed( int key ) { return gameControllerStatus & key; }

关于位运算 bitwise operation

用了很多年C,关于左移和右移操作,经常还是搞不清楚到底操作符在哪边。

这里一次搞明白

C99的定义:

shift-expression:

  additive-expression

  shift-expression<<additive-expression

  shift-expression>>additive-expression

<< 或者 >>的 右侧是具体移动的位数,左边则是被操作数

x = y >> 2; // y 向右移动2位 x = y << 2; // y 向左移动2位 logical shift & arithmic shift 逻辑位移和算数位移

当位移操作和有符号数搞在一起的时候,就需要非常小心。

单纯的shift我们称作logic shift

If the variablechcontains the bit pattern11100101, thench >> 1will produce the result01110010, andch >> 2will produce00111001.

上面的ch,如果以无符号数来表示,则逻辑位移不会影响语义的表达。

但是如果以有符号数表示,则从一个负数变成了一个正数。如果用作乘法操作就非常危险了。

对于C语言,左移和右移是有区别的:
  • 左移永远都是logical shift

A left shift is always a logical shift (the bits that are shifted off the end are discarded, including the sign bit).

  • 右移,在unsigned时是logical shift,在signed时候是arithmic shift : 即会复制之前的符号位到最高位。

For unsigned numbers, the bit positions that have been vacated by the shift operation are zero-filled. For signed numbers, the sign bit is used to fill the vacated bit positions. In other words, if the number is positive, 0 is used, and if the number is negative, 1 is used.

本文共计1264个文字,预计阅读时间需要6分钟。

一文高清字序程序和bit序+大小端的概念大家都很熟悉。这个概念主要针对32bit或64bit机器,多个字节的排序+输出顺序。这个词组非常奇特,了解了输出顺序。The Computer Science term Big-End

一文高清字节序和bit 序

大小端的概念大家都很熟悉了。

这个概念主要是针对 32bit或者 64bit机器中,多个字节的排列顺序

出处

这个词很奇怪,查了下出处。

The Computer Science terms Big-Endian and Little-Endian were introduced by Danny Cohen2in 1980. The key termendianhas its roots in the novel Gulliver’s Travels3by Jonathan Swift4where within a war occurs between two factions who are fighting over which end of a boiled egg should be opened for eating. The big end or the little end. Unsurprisingly, the same said book was the inspiration for the naming of theGulliverlibrary.

可以看到原出处是一个小说,里面描述两股势力因为 吃水煮蛋应该从鸡蛋的哪一端开始吃而发生了战争。类似于咸甜豆腐脑的争端。

Endianness就是指鸡蛋的两头。作者起这个名字,我猜是想代表字节序本质上是一个没有什么实质意义,却又真实存在的分歧。

具体区别

一图流:

个人觉得小端相对来说比较符合直觉:

高位在高地址,低位在低地址。

引发的问题

主要是在32位(或者64位)的机器上,如何解释 2字节或者单字节的数据。

以及一些强制类型转换可能出现的问题

bitwise endianness bit内部的大小端

上面讨论的是,64位机器内部,8个字节的顺序问题

实际上,对于一个字节内部的Bit,也存在一个对称的问题,bit的排列顺序是怎么样的

给定一个结构体:

struct Byte { UINT8 bit0:1; UINT8 bit1:1; UINT8 bit2:1; UINT8 bit3:1; UINT8 bit4:1; UINT8 bit5:1; UINT8 bit6:1; UINT8 bit7:1; };

 问题来了, bit 0 到底是在 Byte的 LSB还是在MSB?换个问的方法,我要修改bit 0, 是 byte |= (1 << 0), 还是byte |= (1 << 7)

简而言之的结论:

不确定。

C99 §6.7.2.1, paragraph 10 says:

"The order of allocation of bit-fields within a unit (high-order to low-order or low-order to high-order) is implementation-defined."

C99标准表示: 具体的bit order和compiler的实现相关。

所以用bit 来表示数据的方式,兼容性需要提个醒。

最安全的方式使用结构体内的成员引用方式。

如果需要显式的表示这些位置,最好用下面的定义方式:

1 /* Each of these preprocessor directives defines a single bit, 2 corresponding to one button on the controller. 3 Button order matches that of the Nintendo Entertainment System. */ 4 #define KEY_RIGHT 0b00000001 5 #define KEY_LEFT 0b00000010 6 #define KEY_DOWN 0b00000100 7 #define KEY_UP 0b00001000 8 #define KEY_START 0b00010000 9 #define KEY_SELECT 0b00100000 10 #define KEY_B 0b01000000 11 #define KEY_A 0b10000000 12 13 int gameControllerStatus = 0; 14 15 /* Sets the gameControllerStatus using OR */ 16 void KeyPressed( int key ) { gameControllerStatus |= key; } 17 18 /* Clears the gameControllerStatus using AND and ~ (binary NOT)*/ 19 void KeyReleased( int key ) { gameControllerStatus &= ~key; } 20 21 /* Tests whether a bit is set using AND */ 22 int IsPressed( int key ) { return gameControllerStatus & key; }

关于位运算 bitwise operation

用了很多年C,关于左移和右移操作,经常还是搞不清楚到底操作符在哪边。

这里一次搞明白

C99的定义:

shift-expression:

  additive-expression

  shift-expression<<additive-expression

  shift-expression>>additive-expression

<< 或者 >>的 右侧是具体移动的位数,左边则是被操作数

x = y >> 2; // y 向右移动2位 x = y << 2; // y 向左移动2位 logical shift & arithmic shift 逻辑位移和算数位移

当位移操作和有符号数搞在一起的时候,就需要非常小心。

单纯的shift我们称作logic shift

If the variablechcontains the bit pattern11100101, thench >> 1will produce the result01110010, andch >> 2will produce00111001.

上面的ch,如果以无符号数来表示,则逻辑位移不会影响语义的表达。

但是如果以有符号数表示,则从一个负数变成了一个正数。如果用作乘法操作就非常危险了。

对于C语言,左移和右移是有区别的:
  • 左移永远都是logical shift

A left shift is always a logical shift (the bits that are shifted off the end are discarded, including the sign bit).

  • 右移,在unsigned时是logical shift,在signed时候是arithmic shift : 即会复制之前的符号位到最高位。

For unsigned numbers, the bit positions that have been vacated by the shift operation are zero-filled. For signed numbers, the sign bit is used to fill the vacated bit positions. In other words, if the number is positive, 0 is used, and if the number is negative, 1 is used.