转:http://www.360doc.com/content/13/0624/10/496343_295125641.shtml

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
Endian First Byte
(lowest address)
Middle Bytes Last Byte
(highest address)
Summary
big most significant ... least significant Similar to a number written on paper (in Arabic numerals)
little least significant ... most significant Arithmetic 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  →
... 0Ah 0Bh 0Ch 0Dh ...

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  →
... 0A0Bh 0C0Dh ...

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  →
... 0Dh 0Ch 0Bh 0Ah ...

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  →
... 0C0Dh 0A0Bh ...

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
... 0Ah 0Bh 0Ch 0Dh ...

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
... 0A0Bh 0C0Dh ...

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. }
结果为: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. return 0;
  16. }
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
  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. d0 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 位序

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

  1. C语言中的位域的使用

    转载:http://blog.sina.com.cn/s/blog_648d306d0100mv1c.html C语言中的位域的使用一.位域 有些信息在存储时,并不需要占用一个完整的字节, 而只需占几 ...

  2. C语言中的位域[转]

    有些信息在存储时,并不需要占用一个完整的字节,而只需要一个或几个二进制位即可;比如:在存放一个开关量时,只有0和1两种状态,只需要使用一个二进制位即可存储;为了节省存储空间,C语言提供了一种数据结构, ...

  3. 关于C语言中的位域

    有些信息在存储时,并不需要占用一个完整的字节, 而只需占几个或一个二进制位.例如在存放一个开关量时,只有0和1 两种状态,用一位二进位即可.为了节省存储空间,并使处理简便,C语言提供了一种数据结构,称 ...

  4. C语言中数据类型的字节数

    类型 16位 32 位 64位 char 1 1 1 short int 2 2 2 int 2 4 4 unsigned int 2 4 4 float 4 4 4 double 8 8 8 lon ...

  5. C语言判断大小端的几种方法

    在操作系统中,经常会用到判断大小端,很多面试题中也会经常遇到,以前的时候没有总结过,这里总结一下. 以后用到了就直接可以用了. 所谓的大小端,大致的解释意思就是: [大端模式] CPU对操作数的存放方 ...

  6. c语言:union,大小端

    union: 不允许只用联合变量名作赋值或其它操作. 也不允许对联合变量作初始化赋值,赋值只能在程序中进行. 小端存储: 以字节为单位,低存低,高存高. 任何数据在内存中都是以二进制(1或着0)顺序存 ...

  7. 用C语言,如何判断主机是 大端还是小端(字节序)

    所谓大端就是指高位值在内存中放低位地址,所谓小端是指低位值在内存中放低位地址.比如 0x12345678 在大端机上是 12345678,在小端机上是 78564312,而一个主机是大端还是小端要看C ...

  8. C语言中的字节对齐以及其相关处理

    首先,我们来了解下一些基本原理: 一.什么是字节对齐一个基本类型的变量在内存中占用n个字节,则该变量的起始地址必须能够被n整除,即: 存放起始地址 % n = 0,那么,就成该变量是字节对齐的;对于结 ...

  9. C语言中的字节对齐

    下面这个篇博客讲解很好 http://blog.csdn.net/meegomeego/article/details/9393783 总的来看分三类: 1. 不加 #pragma pack(n)伪指 ...

随机推荐

  1. [session篇]看源码学习session(一)

    假如你是使用过或学习过PHP,你一定觉得很简单.session只不过是$_SESSION就可以搞得,这还不简单只是对一个key-value就能工作了.我觉得可以大多数的phper都是这样的,这是语言本 ...

  2. Name Disambiguation in AMiner-Clustering, Maintenance, and Human in the Loop

    Name Disambiguation in AMiner: Clustering, Maintenance, and Human in the Loop paper:http://keg.cs.ts ...

  3. ip和子网掩码的判断

     只要记住B类IP的范围就好了(128以下的是A,128~191是B段,192以上是C段) 比如B类,网络地址为前两段,后面两段是主机地址,所以网络标识应该是255.255.0.0

  4. HDU 3480 Division(斜率DP裸题)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3480 题目大意:将n个数字分成m段,每段价值为(该段最大值-该段最小值)^2,求最小的总价值. 解题思 ...

  5. UVA - 796

    UVA- 796 /** 题意:给出一个图,然后看此图的存在的桥,并且输出是哪一个, 做法:Tarjan(不存在重边) **/ #include<iostream> #include< ...

  6. Django-form組件補充

    自定义验证规则 方法一: 1 2 3 4 5 6 7 8 9 10 from django.forms import Form   from django.forms import widgets f ...

  7. redis 安装及安装遇到的问题解决

    https://blog.csdn.net/jy0902/article/details/19248299 http://q.fireflyclub.org/?/article/24 https:// ...

  8. Java学习笔记(一)——关于java中的String类

    [前面的话] 毕业将近6个月了,试用期也快要过去了,期待接下来的日子.在金融类性质的机构,最痛苦的是也许就是大部分系统外包,所以比较少写代码,在这六个月中只写了1个月左右的代码,然后每天都在做一些比较 ...

  9. qtp录制时间控件不允许用户手动输入的解决办法

    qtp录制时间控件不允许用户手动输入的解决办法 [前面的话] 一边学习qtp,一边用自己的项目试着写代码,而遇到一个问题就会让自己卡壳很久,这次也是这样的,在写好了登录代码以后,自己就试着写第一个预订 ...

  10. poj2104 主席树 区间K大 在线 无修改

    关于主席树: 主席树(Chairman Tree)是一种离线数据结构,使用函数式线段树维护每一时刻离散之后的数字出现的次数,由于各历史版本的线段树结构一致,可以相减得出区间信息,即该区间内出现的数字和 ...