草庐IT

位运算和大小端以及位移操作 bitwise & byte Endianness

飞机云_ 2023-03-28 原文

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

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

出处

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

The Computer Science terms Big-Endian and Little-Endian were introduced by Danny Cohen 2 in 1980. The key term endian has its roots in the novel Gulliver’s Travels 3 by Jonathan Swift 4 where 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 the Gulliver library.

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

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 variable ch contains the bit pattern 11100101, then ch >> 1 will produce the result 01110010, and ch >> 2 will produce 00111001.

上面的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.

有关位运算和大小端以及位移操作 bitwise & byte Endianness的更多相关文章

  1. ruby-on-rails - 在 Rails 中将文件大小字符串转换为等效千字节 - 2

    我的目标是转换表单输入,例如“100兆字节”或“1GB”,并将其转换为我可以存储在数据库中的文件大小(以千字节为单位)。目前,我有这个:defquota_convert@regex=/([0-9]+)(.*)s/@sizes=%w{kilobytemegabytegigabyte}m=self.quota.match(@regex)if@sizes.include?m[2]eval("self.quota=#{m[1]}.#{m[2]}")endend这有效,但前提是输入是倍数(“gigabytes”,而不是“gigabyte”)并且由于使用了eval看起来疯狂不安全。所以,功能正常,

  2. ruby-on-rails - rails : "missing partial" when calling 'render' in RSpec test - 2

    我正在尝试测试是否存在表单。我是Rails新手。我的new.html.erb_spec.rb文件的内容是:require'spec_helper'describe"messages/new.html.erb"doit"shouldrendertheform"dorender'/messages/new.html.erb'reponse.shouldhave_form_putting_to(@message)with_submit_buttonendendView本身,new.html.erb,有代码:当我运行rspec时,它失败了:1)messages/new.html.erbshou

  3. ruby-on-rails - 由于 "wkhtmltopdf",PDFKIT 显然无法正常工作 - 2

    我在从html页面生成PDF时遇到问题。我正在使用PDFkit。在安装它的过程中,我注意到我需要wkhtmltopdf。所以我也安装了它。我做了PDFkit的文档所说的一切......现在我在尝试加载PDF时遇到了这个错误。这里是错误:commandfailed:"/usr/local/bin/wkhtmltopdf""--margin-right""0.75in""--page-size""Letter""--margin-top""0.75in""--margin-bottom""0.75in""--encoding""UTF-8""--margin-left""0.75in""-

  4. ruby-on-rails - 'compass watch' 是如何工作的/它是如何与 rails 一起使用的 - 2

    我在我的项目目录中完成了compasscreate.和compassinitrails。几个问题:我已将我的.sass文件放在public/stylesheets中。这是放置它们的正确位置吗?当我运行compasswatch时,它不会自动编译这些.sass文件。我必须手动指定文件:compasswatchpublic/stylesheets/myfile.sass等。如何让它自动运行?文件ie.css、print.css和screen.css已放在stylesheets/compiled。如何在编译后不让它们重新出现的情况下删除它们?我自己编译的.sass文件编译成compiled/t

  5. ruby - 什么是填充的 Base64 编码字符串以及如何在 ruby​​ 中生成它们? - 2

    我正在使用的第三方API的文档状态:"[O]urAPIonlyacceptspaddedBase64encodedstrings."什么是“填充的Base64编码字符串”以及如何在Ruby中生成它们。下面的代码是我第一次尝试创建转换为Base64的JSON格式数据。xa=Base64.encode64(a.to_json) 最佳答案 他们说的padding其实就是Base64本身的一部分。它是末尾的“=”和“==”。Base64将3个字节的数据包编码为4个编码字符。所以如果你的输入数据有长度n和n%3=1=>"=="末尾用于填充n%

  6. ruby-on-rails - 如何从 format.xml 中删除 <hash></hash> - 2

    我有一个对象has_many应呈现为xml的子对象。这不是问题。我的问题是我创建了一个Hash包含此数据,就像解析器需要它一样。但是rails自动将整个文件包含在.........我需要摆脱type="array"和我该如何处理?我没有在文档中找到任何内容。 最佳答案 我遇到了同样的问题;这是我的XML:我在用这个:entries.to_xml将散列数据转换为XML,但这会将条目的数据包装到中所以我修改了:entries.to_xml(root:"Contacts")但这仍然将转换后的XML包装在“联系人”中,将我的XML代码修改为

  7. ruby - 检查 "command"的输出应该包含 NilClass 的意外崩溃 - 2

    为了将Cucumber用于命令行脚本,我按照提供的说明安装了arubagem。它在我的Gemfile中,我可以验证是否安装了正确的版本并且我已经包含了require'aruba/cucumber'在'features/env.rb'中为了确保它能正常工作,我写了以下场景:@announceScenario:Testingcucumber/arubaGivenablankslateThentheoutputfrom"ls-la"shouldcontain"drw"假设事情应该失败。它确实失败了,但失败的原因是错误的:@announceScenario:Testingcucumber/ar

  8. ruby-on-rails - Rails 3.2.1 中 ActionMailer 中的未定义方法 'default_content_type=' - 2

    我在我的项目中添加了一个系统来重置用户密码并通过电子邮件将密码发送给他,以防他忘记密码。昨天它运行良好(当我实现它时)。当我今天尝试启动服务器时,出现以下错误。=>BootingWEBrick=>Rails3.2.1applicationstartingindevelopmentonhttp://0.0.0.0:3000=>Callwith-dtodetach=>Ctrl-CtoshutdownserverExiting/Users/vinayshenoy/.rvm/gems/ruby-1.9.3-p0/gems/actionmailer-3.2.1/lib/action_mailer

  9. ruby-on-rails - 如何优雅地重启 thin + nginx? - 2

    我的瘦服务器配置了nginx,我的ROR应用程序正在它们上运行。在我发布代码更新时运行thinrestart会给我的应用程序带来一些停机时间。我试图弄清楚如何优雅地重启正在运行的Thin实例,但找不到好的解决方案。有没有人能做到这一点? 最佳答案 #Restartjustthethinserverdescribedbythatconfigsudothin-C/etc/thin/mysite.ymlrestartNginx将继续运行并代理请求。如果您将Nginx设置为使用多个上游服务器,例如server{listen80;server

  10. ruby - 在 jRuby 中使用 'fork' 生成进程的替代方案? - 2

    在MRIRuby中我可以这样做:deftransferinternal_server=self.init_serverpid=forkdointernal_server.runend#Maketheserverprocessrunindependently.Process.detach(pid)internal_client=self.init_client#Dootherstuffwithconnectingtointernal_server...internal_client.post('somedata')ensure#KillserverProcess.kill('KILL',

随机推荐