【转】C语言中的位域、字节序、比特序、大小端

2023-05-16

1.比特序 / 位序 /  bit numbering / bit endianness
 

我们知道一个字节有8位,也就是8个比特位。从第0位到第7位共8位。比特序就是用来描述比特位在字节中的存放顺序的。通过阅读网页http://en.wikipedia.org/wiki/Bit_numbering的内容,关于比特序我们得到下面的结论:

(1)比特序分为两种: LSB 0  位序MSB 0  位序
     LSB是指  least significant bit,MSB是指  most significant bit。
LSB 0  位序是指:字节的第0位存放数据的 least significant bit,即我们的数据的 最低位存放在字节的第0位。
MSB 0  位序是指:字节的第0位存放 数据的most significant bit,即我们的数据的 最高位存放在字节的第0位。
 
所以说对于代码:char *ch = 0x96;  //  0x96 = 1001 0110
 
指针ch到底指向哪里呢?不难知道,如果是 LSB 0  位序则显然指针ch指向 最右边的也是 最低位的0.
而如果是 MSB 0  位序则显然指针ch指向 最左边的也是 最高位的1.
LSB 0: A container for 8-bit binary number with the highlighted  least significant bit assigned the bit number 0
 
MSB 0:A container for 8-bit binary number with the highlighted  most significant bit assigned the bit number 0
 
(2) 小端CPU通常采用的是LSB 0 位序,但是大端CPU却有可能采用 LSB 0  位序也有可能采用的是 MSB 0  位序
        ( Little-endian CPUs usually employ "LSB 0" bit numbering, however both bit numbering conventions can be seen in  big-endianmachines. )
(3)推荐的标准是 MSB 0  位序。
        (The recommended style for  Request for Comments documents is "MSB 0" bit numbering.)
(4)Bit numbering is usually transparent to the  software.
 
2.大小端和字节序    http://en.wikipedia.org/wiki/Endianess
In computing, the term endian or endianness refers to the ordering of individually addressable sub-components within the representation of a larger data item as stored in external memory (or, sometimes, as sent on a serial connection). Each sub-component in the representation has a unique degree of significance, like the place value of digits in a decimal number. These sub-components are typically 16- or 32-bit words, 8-bit bytes, or even bits. Endianness is a difference in data representation at the hardware level and may or may not be transparent at higher levels, depending on factors such as the type of high level language used.
计算机中,术语“端”是指:在内存中的一个较大的数据,它是由各个可以被单独寻址的部分组成,这些组成部分在该数据中是以怎样的顺序存放的呢?而这个问题涉及到“端”的概念, CPU是大端还是小端决定了这些组成部分的存放顺序
这些组成部分可能是16或32位的字、8位的字节、甚至是比特位。
The most common cases refer to how bytes are ordered within a single 16-, 32-, or 64-bit word。
我们通常碰到的情况是:字节是以怎样的顺序存放在一个16、32、64位的数据中
(当我们要存取一个16、32、64位数据的某一组成部分,也就是某一个或几个字节时,就要特别注意机器的“大小端”)
 A big-endian machine stores the most significant byte first, and a little-endian machine stores the least significant byte first.
Quick Reference - Byte Machine Example
EndianFirst Byte
(lowest address)
Middle BytesLast Byte
(highest address)
Summary
bigmost significant...least significantSimilar to a number written on paper (in Arabic numerals)
littleleast significant...most significantArithmetic calculation order (see carry propagation)

Examples of storing the value 0A0B0C0Dh in memory
Big-endian Atomic element size 8-bit, address increment 1-byte (octet)
increasing addresses  →
...0Ah0Bh0Ch0Dh...

The most significant byte (MSB) value, which is 0Ah in our example, is stored at the memory location with the lowest address, the next byte value in significance, 0Bh, is stored at the following memory location and so on. This is akin to Left-to-Right reading in hexadecimal order.

Atomic element size 16-bit
increasing addresses  →
...0A0Bh0C0Dh...

The most significant atomic element stores now the value 0A0Bh, followed by 0C0Dh.

Little-endian Atomic element size 8-bit, address increment 1-byte (octet)
increasing addresses  →
...0Dh0Ch0Bh0Ah...

The least significant byte (LSB) value, 0Dh, is at the lowest address. The other bytes follow in increasing order of significance.

Atomic element size 16-bit
increasing addresses  →
...0C0Dh0A0Bh...

The least significant 16-bit unit stores the value 0C0Dh, immediately followed by 0A0Bh. Note that 0C0Dh and 0A0Bh represent integers, not bit layouts (see bit numbering).

很显然“小端”机器符合“高高低低”的原则。及高位字节或字存放在高地址,低位字节或字存放在低地址。
另外“小端”机器中,数据在CPU的寄存器和内存中的存放顺序是一致的。
 
Byte addresses increasing from right to left
在我们写: 0xFF86 时,很明显地址是从右向左递增的。也就是低位写在右边,高位写在左边。
但是当我们写字符串时:char *str = "Hello world!",却是低位的字符写在左边,高位的字符写在了右边。
With 8-bit atomic elements:
←  increasing addresses
...0Ah0Bh0Ch0Dh...

The least significant byte (LSB) value, 0Dh, is at the lowest address. The other bytes follow in increasing order of significance.(这个明显符合我们的习惯)

With 16-bit atomic elements:

←  increasing addresses
...0A0Bh0C0Dh...

The least significant 16-bit unit stores the value 0C0Dh, immediately followed by 0A0Bh.

The display of text is reversed from the normal display of languages such as English that read from left to right. For example, the word "XRAY" displayed in this manner, with each character stored in an 8-bit atomic element:

←  increasing addresses
..."Y""A""R""X"...
可以看到和我们手写的顺序是相反的,这一点特别要注意!) 

If pairs of characters are stored in 16-bit atomic elements (using 8 bits per character), it could look even stranger:

←  increasing addresses
..."AY""XR"...

相关的一个C例子:
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. int main()
  5. {
  6.         char a[] = {'a', 'b', 'c'};
  7.         char b[] = {'d', 'e', 'f'};
  8.         a[3] = 0;
  9.         printf("strlen(a)=%d, strlen(b)=%d\n", strlen(a), strlen(b));
  10.         printf("a=%s, b=%s\n", a, b);
  11.         printf("sizeof(a)=%d, sizeof(b)=%d\n", sizeof(a), sizeof(b));
  12.         return 0;
  13. }
运行结果:
strlen(a)=3, strlen(b)=6
a=abc, b=defabc
sizeof(a)=3, sizeof(b)=3
分析:
字符数组a和b都分配在栈上,先分配a, 而a中的字符是如何分配的呢?显然因为“写字符串时,低位的字符写在左边,高位的字符写在了右边”。'a'是最低位,'b'在中间,而'c'在最高位。而栈是从高地址从低地址扩展的。假如是小端CPU的话,按照“高高低低”的原则,高位的'c'应该最先分配,接着是'b',最后是'a'。
分配玩字符数组a之后,在分配字符数组b,同样的道理,高位的'f'应该最先分配,接着是'e',最后是'd'。
再执行a[3] = 0;显然a[3]的地址应该比'c'字符的地址要高。所以该语句执行玩之后的栈的情况如下:
高地址 <<---- 低地址
\0   c   b   a   f   e   d
所以:a字符打印的结果是:abc,而b字符打印的结果是:defabc.
strlen函数是计算字符的长度,当然要找到最后的结束字符'\0',才停止计算。所以字符a的长度是3,而字符b的长度是6.
sizeof并不根据末尾的结束字符来计算大小。
 例子2:
  1. #include <stdio.h>
  2. int main()
  3. {
  4.         unsigned long array[] = {0x12345678, 0xabcdef01, 0x456789ab};
  5.         unsigned short ret;
  6.         ret = *((unsigned short *)((unsigned long)array+7));
  7.         printf("0x%x\n", ret);
  8.         return 0;
  9. }
在“小端”CPU上结果为:0xabab。在“大端”CPU上应该为:0x0112.
例子3:
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. int main(void){
  4.     int a[5]={1,2,3,4,5};
  5.     int *ptr =(int *)(&a+1);
  6.     printf("%d,%d\n",*(a+1),*(ptr-1))
  7.     return 0;
  8.     
  9. }
结果为:2,5 (此题与“大小端”无关。)
 
判断CPU是大端还是小端的方法有有多种:
  1. #include <stdio.h>
  2. #include <assert.h>
  3. int main()
  4. {
  5.     unsigned short x = 0xff01;
  6.     assert(sizeof(x) >= 2);
  7.     if(*(char*)&x == 1) //if(char(x) == 1)
  8.         printf("little-endian\n");
  9.     else if((char)x > 1)
  10.         printf("big-endian\n");
  11.     else
  12.         printf("unknown\n");
  13.     return 0;
  14. }
方法2:
  1. #include <stdio.h>
  2. int main()
  3. {
  4.         union{
  5.                 char c;
  6.                 int i;
  7.         }u;
  8.         u.i = 0x0201;
  9.         if(u.c == 1)
  10.                 printf("little-endian\n");
  11.         else if(u.c == 2)
  12.                 printf("big-endian\n");
  13.         else
  14.                 printf("unknown\n");
  15.         
  16.         return 0;
  17. }
3.C语言中的位域
先看几个例子:
  1. #include <stdio.h>
  2. union u{
  3.         struct {
  4.                 char i:1;
  5.                 char j:2;
  6.                 char m:3;
  7.         } s;
  8.         char c;
  9. }r;
  10. int main()
  11. {
  12.         r.s.i = 1; // 1
  13.         r.s.j = 2; // 10
  14.         r.s.m = 3; // 011
  15.         printf("0x%x\n", r.c);
  16.         return 0;
  17. }
gcc -o union union.c
./union
结果:0x1d (== 0001 1101 == 011 10 1
  1. #include <stdio.h>
  2. union {
  3.     struct
  4.     {
  5.         unsigned char a1:2;
  6.         unsigned char a2:3;
  7.         unsigned char a3:3;
  8.     }x;
  9.     unsigned char b;
  10. }d;
  11. int main(int argc, char* argv[])
  12. {
  13.     d.b = 100;   //100 == 0110 0100
  14.     printf("0x%x\n0x%x\n0x%x\n", d.x.a1, d.x.a2, d.x.a3);
  15.     return 0;
  16. }
gcc -o union2 union2.c
 
结果:
0x0 (== 00
0x1 (== 001
0x3 (== 011
上面两个例子的运行结果,似乎都说明:小端机器中, 位域的低位组成数据的低位,位域的高位组成了数据的高位

似乎也符合:小端CPU通常采用的是LSB 0 位序 的惯例。

但是这里有意个疑问:在大端CPU中,上面两个例子的结果是什么呢?结果和小端CPU一样吗?结果唯一吗?

因为前面我们说过:“但是大端CPU却有可能采用LSB 0 位序也有可能采用的是MSB 0 位序

 

原文地址:http://blog.chinaunix.net/uid-25909722-id-2749575.html

转载于:https://www.cnblogs.com/russellluo/archive/2012/06/09/2543364.html

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

【转】C语言中的位域、字节序、比特序、大小端 的相关文章

随机推荐

  • github,源码,高仿 直播

    仿花田 xff1a 相亲网站 意中人 已在GitHub上开源 从头开始写一款开源app上线 相互学习 SlideMenuControllerSwift swift实现双侧边栏菜单 StepView github 物流信息 iOS 常用控件集
  • 一文搞懂RAM、ROM、SDRAM、DRAM、DDR、flash等存储介质

    一文搞懂RAM ROM SDRAM DRAM DDR flash等存储介质 存储介质基本分类 xff1a ROM和RAM RAM xff1a 随机访问存储器 Random Access Memory xff0c 易失性 是与CPU直接交换数
  • IDEA解决从git上clone代码没有maven依赖的问题

    首先 xff0c 从git上拉取代码 xff1a 我们将新clone下来的项目打开 xff0c 可以发现在git上原本是maven项目的工程 xff0c 没有了maven的结构 xff1a 要解决这个问题 xff0c 我们需要关闭这个项目
  • python plt画图横纵坐标0点重合

    coding utf 8 import numpy as np import matplotlib mlab as mlab import matplotlib pyplot as plt from scipy import optimiz
  • Fiji-imageJ 无法打开

    可能的原因是文件的路径包含中文名称 转载于 https www cnblogs com cmyg p 11408207 html
  • The type name or alias SqlServer could not be resolved.Please check your configuration

    The type name or alias SqlServer could not be resolved Please check your configuration file 检查一下Config文件中包含的dll再dubug文件夹
  • 总结记录一下如何统计CPU使用情况、磁盘利用率

    一 cpu使用率 可以使用 proc stat命中查看 举例 xff1a cat proc stat grep cpu cpu 1391321772 178 2524194226 33711208592 1046582 6540 38867
  • LCD1602屏幕简介(全网最详细教程)

    目录 1 接线说明 2 LCD1602显示原理 3 LCD1602时序分析 4 LCD1602显示一个字符 5 LCD1602显示一行 1 接线说明 第1引脚 xff1a GND为电源地 第2引脚 xff1a VCC接5V电源正极 第3引脚
  • .Net Core 获取上下文HttpContext

    1 先定义一个类 using Microsoft AspNetCore Http namespace BCode Util public class MvcContext public static IHttpContextAccessor
  • XML有关知识

    可扩展标记语言 起初w3c为了严格语法 xff08 html在各个浏览器的恶性竞争下语法已经变得很松散了 xff09 推出了xml 功能 xff1a 存储数据 xff0c 1 配置文件使用 2 在网络中传输 转载于 https www cn
  • pixhawk代码移植到不同stm32芯片

    本文基于pixhawk1 0 1代码 xff0c 移植需要的知识很多 xff0c 一两个文章可说不清楚 xff0c 里面涉及到编译原理 xff0c 操作系统 xff0c stm32 xff0c 计算机组成原理等 xff0c 需要长期积累 x
  • 转 Pycharm及python安装详细教程

    转 xff1a http blog csdn net qq 29883591 article details 52664478 首先我们来安装Python 1 首先进入网站下载 xff1a 点击打开链接 xff08 或自己输入网址https
  • Python基础(6)——实现输入任意多个数,并计算其平均值

    学习了Python相关数据类型 xff0c 函数的知识后 xff0c 利用字符串的分割实现了输入任意多个数据 xff0c 并计算其平均值的小程序 思路是接收输入的字符串 xff0c 以空格为分隔符 xff0c 将分割的数据存入列表 xff0
  • 校园网破解

    今天刷酷安看到了校园网破解 xff0c 正好有时间研究下 首先了解一下校园网的机制 平时在家用的wifi均为外部网进来接路由器LAN端口 xff0c 在路由器里填入你的宽带账号密码 xff0c 开启DHCP即可 这里的校园进来插到了LAN口
  • 绝命毒师第一季/全集Breaking Bad迅雷下载

    本季Breaking Bad Season 1 2008 看点 xff1a 新墨西哥州的高中化学老师沃尔特 H 怀特 xff08 布莱恩 科兰斯顿 Bryan Cranston 饰 xff09 是拮据家庭的唯一经济来源 他大半生安分守己 x
  • Linux 释放socket资源,LwIP使用select,close socket资源释放不完全问题

    这篇文章本应该在4月就写好的 xff0c 但是博客评论系统一直没有搭建好 xff0c 走了很多弯路 xff0c 现在好了 xff0c delay这么久 xff0c 终于要要补过来了 自建博客 xff1a 金宝的博客 该文章完全原创 xff0
  • __FILE__,__LINE__,__DATE__,__TIME__ c++常用的预定义名字

    C 43 43 有四个常用的预定义名字 xff0c 分别为 FILE LINE DATE TIME FILE 记录文件的路径加名称 LINE 记录文件已经被编译的行数 DATE 记录文件的编译日期 TIME 记录文件的编译时间 可以当作变量
  • 串口拓展

    今天桌子下面找出一个破电路板看到一颗芯片GM8125 xff0c 这个芯片主要功能就是拓展串口 GM8125可以将一个全双工的标准串口扩展成5个标准串口 xff0c 并能通过外部引脚控制串口扩展模式 xff1a 单通道工作模式和多通道工作模
  • HttpUtils

    package com rs zero crc common http import com rs zero crc modulars common constants SysConstantConf import com xiaoleil
  • 【转】C语言中的位域、字节序、比特序、大小端

    1 比特序 位序 bit numbering bit endianness 我们知道一个字节有8位 xff0c 也就是8个比特位 从第0位到第7位共8位 比特序就是用来描述比特位在字节中的存放顺序的 通过阅读网页http en wikipe