//假设硬件平台是intel x86(little endian)    

 typedef unsigned int uint32_t;
void inet_ntoa(uint32_t in)
{
char b[];
register char *p;
p = (char *)∈
#define UC(b) (((int)b)&0xff)
sprintf(b, "%d.%d.%d.%d/n", UC(p[]), UC(p[]), UC(p[]), UC(p[]));
printf(b);
}
int main()
{
inet_ntoa(0x12345678);
inet_ntoa(0x87654321);
}

有点难度的一道题目,其实理解的也很简单。

位域(Bit-fields)分析

位域是c++和c里面都有的一个概念,但是位域有一点要注意的有很多问题我们一样样的看:

大端和小端字节序

这个很简单,就是起始点该怎么确定。
先看一个程序:

     union {
struct
{
unsigned char a1:;
unsigned char a2:;
unsigned char a3:;
}x;
unsigned char b;
}d;
int main(int argc, char* argv[])
{
d.b = ;
return ;
}

那么x的a1,a2,a3该怎么分配值,100的二进制是:0110 0100,那么a1到a3是不是就是依次取值恩?
不是!
我们先看看100分配位的低端是左边的0还是右边的0?很明显是右边的0,那么我们再看a1到a3的分配是从低端到高端的
那么,对应的应该是
<<<<<<--内存增大
a3   a2  a1
011  001 00

内存增大之所以这么写是因为,011是在高位!
而不是通常认为的的:
a1   a2  a3
011  001 00

还有一个情况多见就是一个二进制的数字转化为点分十进制数值,如何进行,这里涉及到大端还是小端的问题,上面没有涉及,主要是因为上面是一个字节,没有这个问题,多个字节就有大端和小端的问题了,或许我们应该记住这一点就是,在我们的计算机上面,大端和小端都是以字节为准的,当然严格来说更应该以位为准不是吗?具体可以参考维基百科上面的一篇文章,他给出了一个以位为准的大小端序的图:

http://en.wikipedia.org/wiki/Endianess

下面研究字节为单位的大小端序,继续看代码吧,如下:

     int main(int argc, char* argv[])
{
int a = 0x12345678;
char *p = (char *)&a;
char str[];
sprintf(str,"%d.%d.%d.%d", p[], p[], p[], p[]);
printf(str);
return ;
}

这个程序假设是小端字节序,那么结果是什么?
我们看看应该怎么放置呢?
每个字节8位,0x12345678分成4个字节,就是从高位字节到低位字节:12,34,56,78,那么这里该怎么放?如下:
---->>>>>>内存增大
78 56 34 12

因为这个是小端,那么小内存对应低位字节,就是上面的结构。

接下来的问题又有点迷糊了,就是p怎么指向,是不是指向0x12345678的开头--12处?不是!12是我们所谓的开头,但是不是内存

的开始处,我们看看内存的分布,我们如果了解p[0]到p[1]的操作是&p[0]+1,就知道了,p[1]地址比p[0]地址大,也就是说p的地址

也是随内存递增的!

12 ^ p[3]
    |
34 | p[2]
    |
56 | p[1]
    |
78 | p[0]
内存随着箭头增大!同时小端存储也是低位到高位在内存中的增加!
这样我们知道了内存怎么分布了

那么:

    sprintf(str,"%d.%d.%d.%d", p[], p[], p[], p[]);

str就是这个结果了:
120.86.52.18

那么反过来呢?

     int main(int argc, char* argv[])
{
int a = 0x87654321;
char *p = (char *)&a;
char str[];
sprintf(str,"%d.%d.%d.%d", p[], p[], p[], p[]);
printf(str);
return ;
}

依旧是小端,8位是一个字节那么就是这样的啦:

87 ^ p[3]
     |
65 | p[2]
    |
43 | p[1]
    |
21 | p[0]

结果是:
33.67.101.-121
为什么是负的?因为系统默认的char是有符号的,本来是0x87也就是135,大于127因此就减去256得到-121
那么要正的该怎么的弄?
如下就是了:

     int main(int argc, char* argv[])
{
int a = 0x87654321;
unsigned char *p = (unsigned char *)&a;
char str[];
sprintf(str,"%d.%d.%d.%d", p[], p[], p[], p[]);
printf(str);
return ;
}

用无符号的!
结果:
33.67.101.135

位域的符号(正负)

看完大端和小端以后,再看看位域的取值的问题,上面我们谈到了一些,首先就是位域是按照位来取值的跟我们的int是32位char是8

位一样,很简单,但是,要注意一点就是位域也有正负,指有符号属性的,就是最高位表示的,也会涉及到补码这个一般被认为非常

恶心的东西,看看程序吧:

     #include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char** argv)
{
union
{
struct
{
unsigned char a:;
unsigned char b:;
unsigned char c:;
}d;
unsigned char e;
} f;
f.e = ;
printf("%d/n",f.d.a);
return ;
}

<小端>
那么输出是什么?
换一下:

     #include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char** argv)
{
union
{
struct
{
char a:;
char b:;
char c:;
}d;
char e;
} f;
f.e = ;
printf("%d/n",f.d.a);
return ;
}

输出又是什么?

小端的话,那么,再d.a上面分得1,而这个是无符号的char,那么前者输出是1,没有问题,第二个输出是-1,哈哈。
为什么?
第二个是无符号的,就一个位分得1,那么就是最高位分得1,就是负数,负数用的补码,实际的值是取反加1,就是0+1=1,再取符

号负数,就是-1.

整型提升

最后的打印是用的%d,那么就是对应的int的打印,这里的位域肯定要提升,这里有一点,不管是提升到有符号还是无符号,都是自

己的符号位来补充,而不改变值的大小(这里说的不改变值大小是用相同的符号属性来读取),负数前面都补充1,正数都是用0来补充

,而且也只有这样才能保证值不变,比如,char提升到int就是前面补充24个char的最高位,比如:

     char c = 0xf0;
int p = c;
printf("%d %d/n",c,p);

输出:-16 -16
p实际上就是0xfffffff0,是负数因此就是取反加1得到
c是一个负数那么转化到x的时候就是最高位都用1来代替,得到的数不会改变值大小的。
再看:

     char c = 0xf0;
unsigned int x = c;
printf("%u/n",x);

得到的结果是4294967280,也就是0xfffffff0,记住,无符号用%u来打印。

地址不可取

最后说的一点就是位域是一个字节单元里面的一段,是没有地址的!

 struct BitField
{
unsigned char a:; //最低位;
unsigned char b:;
unsigned char c:; //最高位;
};
union Union
{
struct BitField bf;
unsigned int n;
};
union Union ubf;
ubf.n = ; //初始化;
ubf.bf.a = ; //二进制为: 000
ubf.bf.b = ; //二进制为: 000
ubf.bf.c = ; //二进制为: 001
printf("ubf.bf.n = %u\n", ubf.n);
 #include <iostream>
#include <memory.h>
using namespace std;
struct A
{
int a:;
int b:;
};
int main(void)
{
char str[] = "0134324324afsadfsdlfjlsdjfl";
struct A d;
memcpy(&d, str, sizeof(A));
cout << d.a << endl;
cout << d.b << endl;
return ;
}

在32位x86机器上输出:

高位 00110100 00110011   00110001    00110000 低位
'4' '3' '1' '0'
其中d.a和d.b占用d低位一个字节(00110000),d.a : 10000, d.b :

解析:在默认情况下,为了方便对结构体内元素的访问和管理,当结构体内的元素长 度都小于处理器的位数的时候,便以结构体里面最长的元素为对其单位,即结构体的长度一定是最长的数据元素的整数倍;如果有结构体内存长度大于处理器位数的 元素,那么就以处理器的位数为对齐单元。由于是32位处理器,而且结构体中a和b元素类型均为int(也是4个字节),所以结构体的A占用内存为4个字 节。

上例程序中定义了位域结构A,两个个位域为a(占用5位),b(占用3位),所以a和b总共占用了结构A一个字节(低位的一个字节)。

当程序运行到14行时,d内存分配情况:

 高位 00110100 00110011   00110001    00110000 低位
'4' '3' '1' '0'
其中d.a和d.b占用d低位一个字节(00110000),d.a : 10000, d.b : 001

d.a内存中二进制表示为10000,由于d.a为有符号的整型变量,输出时要对符号位进行扩展,所以结果为-16(二进制为11111111111111111111111111110000)

d.b内存中二进制表示为001,由于d.b为有符号的整型变量,输出时要对符号位进行扩展,所以结果为1(二进制为00000000000000000000000000000001)

 #include "stdio.h"

 void main(int argn ,char *argv)
{
struct test {
unsigned a:;
unsigned b:;
unsigned c:;
unsigned :;//this two bytes can't use
unsigned d:;
}data,*pData;
data.a=0x177;
data.b=0x111;
data.c=0x7;
data.d=0x8; pData=&data;
printf("data.a=%x data.b= %x data.c=%x data.d=%xn",pData->a,pData->b,pData->c,pData->d);//位域可以使用指针 printf("sizeof(data)=%dn",sizeof(data)); //4 bytes ,最常用的情况 struct testLen{
char a:;
char b:;
char c:;
char d:;
char e:;
}len; printf("sizeof(len)=%dn",sizeof(len)); //5bytes 规则2 struct testLen1{
char a:;
char b:;
char d:;
char c:;
char e:;
}len1;
printf("sizeof(len1) =%dn",sizeof(len1)); //3bytes 规则1 struct testLen2{
char a:;
char :;
char b:;
long d:; //4bytes
char e:;
}len2;
printf("sizeof(len2)=%dn",sizeof(len2)); //12 规则3,4,5,总长为4的整数倍,2+3 占1byte,b占1bye 由于与long对其,2+3+7 占4字节,后面 d 与 e进行了优化 占一个4字节 struct testLen3{
char a:;
char :;
char b:;
long d:;
char e:;
}len3;
printf("sizeof(len3)=%dn",sizeof(len3));//12 规则3,4,5,总长为4的整数倍,2+3 占1byte,b占1bye 由于与long对其,2+3+7 占4字节,后面 d占一个4字节,为了保证与long对其e独占一个4字节
}

C/C++ 位域的更多相关文章

  1. C语言中struct位域的定义和使用

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

  2. C语言位域

    转载自 http://tonybai.com/2013/05/21/talk-about-bitfield-in-c-again/ 再谈C语言位域 五 21 bigwhite技术志 bitfield, ...

  3. C/C++: C++位域和内存对齐问题

    1. 位域: 1. 在C中,位域可以写成这样(注:位域的数据类型一律用无符号的,纪律性). struct bitmap { unsigned a : ; unsigned b : ; unsigned ...

  4. 全面总结sizeof的用法(定义、语法、指针变量、数组、结构体、类、联合体、位域位段)

    一.前言 编译环境是vs2010(32位). <span style="font-size:18px;">#include<iostream> #inclu ...

  5. C 结构体位域

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

  6. 关于C语言中的位域

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

  7. C语言中结构体的位域(bit-fields)

    转自:http://blog.sina.com.cn/s/blog_6240b5980100tcba.html 有些信息在存储时,并不需要占用一个完整的字节, 而只需占几个或一个二进制位.例如在存放一 ...

  8. 位域 unsigned int a : 4;

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

  9. 不可或缺 Windows Native (9) - C 语言: 动态分配内存,链表,位域

    [源码下载] 不可或缺 Windows Native (9) - C 语言: 动态分配内存,链表,位域 作者:webabcd 介绍不可或缺 Windows Native 之 C 语言 动态分配内存 链 ...

随机推荐

  1. bootstrap布局 网格系统

    Bootstrap 网格系统 本章节我们将讲解 Bootstrap 的网格系统(Grid System). Bootstrap 提供了一套响应式.移动设备优先的流式网格系统,随着屏幕或视口(viewp ...

  2. BI之SSAS完整实战教程1 -- 开篇, BI简介 & SSAS简介

    文章提纲 商业智能(BI, Business Intelligence)基本概念 SSAS(SQL Server Analysis Services)相关工具(开发.管理和客户端) 总结 一.商业智能 ...

  3. sql:Oracle11g 表,视图,存储过程结构查询

    -- Oracle 11 G --20160921 涂聚文再次修改 --Geovin Du --GetTables SELECT owner, object_name, created FROM al ...

  4. FreeBSD 9.1安装KMS 这是一个伪命题###### ,9....

    FreeBSD 9.1安装KMS 这是一个伪命题###### ,9.1的内核已经加入了KMS内核支持 需要更新ports中的xorg到打了补丁的版本,无意中发现了一个pkg源,这个事也搞定了 free ...

  5. 线段树或树状数组---Flowers

    题目网址:http://acm.hdu.edu.cn/showproblem.php?pid=4325 Description As is known to all, the blooming tim ...

  6. fibonacci高精度加法

    A Fibonacci sequence is calculated by adding the previous two members the sequence, with the first t ...

  7. 亲们! 首次见面! 带来不适!多多见谅!--------->>Bank系统

    亲们!您们好! 讲一下Bank系统的做法: 01.首先创建一个Card类 using System; using System.Collections.Generic; using System.Li ...

  8. windows下使用makecert命令生成自签名证书

    1.makecert命令路径 C:\Program Files (x86)\Windows Kits\8.1\bin\x64 2.生成一个自签名证书 makecert -r -pe -n " ...

  9. java系统库性能优化注意点

    对于大部分的应用系统开发来说,微秒级别的优化通常是被忽略不计或者不关心的,因为有着更多优化点,但是对于开发供应用系统使用的公用库来说,大部分的操作通常都是对字符.数字.字符串.字节的操作,且这些系统库 ...

  10. galera cluster DDL节点间状态不一致的问题

    近期某个系统中的galera cluseter环境发生A DDL操作后,B节点未同步的情况,同时B节点的errorlog中有如下警告信息: 2016-07-23 17:31:32 18920 [War ...