现在的位置: 首页 > 综合 > 正文

联合+结构+大小端+字节对齐

2012年11月07日 ⁄ 综合 ⁄ 共 5568字 ⁄ 字号 评论关闭

联合(union)与结构的区别是:结构变量的各成员同时被分配了各自独立的内存区,而联合变量的各个成员的存储开始地址都相同,所以在任一时刻联合变量只能存储一个成员。系统为联合变量分配空间时按需要最大存储量的成员大小分配内存空间。

联合被称为一种特殊的类(它因编译器不能知道成员的类型,而没有构造函数和析构函数,所以联合的对象不是由构造函数生成的。故称特殊的类)。

例1:

#include "stdafx.h"
#include<iostream>
using namespace std;
int _tmain(int argc, _TCHAR* argv[])
{   
	//在Windows下,栈是向低地址扩展的数据结构,是一块连续的内存的区域。ch作为一个整体被分配到内存中,在ch中ch[0]存放在低地址;
	char ch[2];
	int i;
	cout.unsetf( ios_base::dec );
	cout.setf( ios_base::hex );
	cout<<(int)&(ch[0])<<endl;
	cout<<(int)&(ch[1])<<endl;
	cout<<(int)&i<<endl;


	union Node
	{
		short sVar;
		char cVar[2];
	};
	Node node;
	node.cVar[0]=2;
	node.cVar[1]=1;

	cout.setf(ios_base::dec);
	cout<<node.sVar<<endl;


	system("pause");
	return 0;
}

解析:
    结构变量的各成员同时被分配了各自独立的内存区,而联合变量的各个成员的存储开始地址都相同,所以在任一时刻联合变量只能存储一个成员。联合体是一种节省空间的类一种节省内存的机制
     short  a    占两个字节
     char  ch[2] 占两个字节
     那么,在这里即就是:只为一个结构对象分配两个字节,当对数组赋值的时候,可以对同一个内存通过另外的成员进行访问。0000
0001  0000  0010 ==  2+256=258

结构体详细解释

<1>数组是为了更清晰的记录有限个相同类型的数据信息而诞生的一种表示形式;结构体是为了更清晰的记录一个具有不同类型属性特性的对象而诞生的一种表示形式

      联合与结构都是由多个不同的数据类型成员组成, 但在任何同一时刻,联合中只存放了一个被选中的成员, 而结构的所有成员都存在。也就是说结构体是对数组在“横向”的扩充,而联合是对结构体在“纵向”的收敛。任何事物的出现都是有一定原因的,而且是可以由逻辑推理而成立的。
<2>在C++中结构体是与类没有太大的区别的。唯一的一个明显的区别就是:struct默认是public而class默认是private。
<3>结构体的定义,举例说明如下:

 1      //第一种   定义结构体类型变量名方式:
 2     struct student          //struct为关键字,不能省略。student为定义的类型为结构体的变量名,一般要求"见名知意"//
 3     {
 4         int num;                //学号用整型的变量名num定义//
 5         char name[30];      //姓名用字符数组型的变量名name定义,长度为30//
 6         char sex;              //性别用字符型的变量名 sex定义//
 7         int age;                //年龄用整型的变量名age定义//
 8         float score;           //成绩用实型的变量名score定义//
 9         char addr[30];       //地址用字符数组型的变量名addr定义//
10     };
11     struct  student stu1,stu2;  //定义结构体类型变量
12   
13     
14     
15     //第二种   定义结构体类型变量名方式:
16 
17         struct student          //struct为关键字,不能省略。student为定义的类型为结构体的变量名,一般要求"见名知意"//
18         {
19         int num;                   //学号用整型的变量名num定义
20         char name[30];         //姓名用字符数组型的变量名name定义,长度为30
21         char sex;                //性别用字符型的变量名 sex定义
22         int age;                  //年龄用整型的变量名age定义
23         float score;             //成绩用实型的变量名score定义
24         char addr[30];   
     
//地址用字符数组型的变量名addr定义
25         }    student1,student2;     
26                                      //直接定义结构体类型变量,变量名为student1,student2
27     
28         
29         
30    //第三种  结构体中的成员也可以是某种结构体//
31         struct date     //日期结构//
32         {
33             int month;   //整型类型 月  month//
34             int day;     //整形类型 日  day//
35             int year;    //整形类型 年  year//
36         };
37 
38       struct student          //struct为关键字,不能省略。student为定义的类型为结构体的变量名,一般要求"见名知意"//
39         {
40              int num;            //学号用整型的变量名num定义//
41              char name[30];      //姓名用字符数组型的变量名name定义,长度为30//
42              char sex;              //性别用字符型的变量名 sex定义//
43              int age;                //年龄用整型的变量名age定义//
44             float score;           //成绩用实型的变量名score定义//
45             char addr[30];    
  
//地址用字符数组型的变量名addr定义//
46             struct date birthday;   //生日用结构体类型变量名birthday定义//
47         };   


<4>结构体的赋值

 1   struct student          //struct为关键字,不能省略。student为定义的类型为结构体的变量名,一般要求"见名知意"//
 2     {
 3         int num;            //学号用整型的变量名num定义//
 4         char name[30];      //姓名用字符数组型的变量名name定义,长度为30//
 5         char sex;           //性别用字符型的变量名 sex定义//
 6         int age;            //年龄用整型的变量名age定义//
 7         float score;        //成绩用实型的变量名score定义//
 8         char addr[30];      //地址用字符数组型的变量名addr定义//
 9     };
10    struct  student  stu1={1001,"liu yong",'M',22,95.5,"shan xi sheng"

大小端判断

首先看一道面试题:请写一个C函数,若处理器是Big_endian的,则返回0;若是Little_endian的,则返回1。
分析:
       为什么会有大小端模式之分呢?这是因为在计算机系统中,我们是以字节为单位的,每个地址单元都对应着一个字节,一个字节为
8bit。但是在C语言中除了8bit的char之外,还有16bit的short型,32bit的long型(要看具体的编译器),另外,对于位数大于 8位的处理器,
例如16位或者32位的处理器,由于寄存器宽度大于一个字节,那么必然存在着一个如何将多个字节安排的问题。因此就导致了大端存储模式和小端存储模式。
     例如一个16bit的short型x,在内存中的地址为0x0010,x的值为0x1122,那么0x11为高字节,0x22为低字节。
     对于大端模式,就将0x11放在低地址中,即0x0010中,0x22放在高地址中,即0x0011中。
     
小端模式,刚好相反。我们常用的X86结构是小端模 式,而KEIL C51则为大端模式。

     嵌入式开发对大小端都比较敏感。所谓的大端模式是指:数据的低位(就是权值较小的后面那几位)保存在内存的高地址中,而数据的高位,保存在内存的低地址中。这样的存储模式有点儿类似于把数据当作字符串顺序处理:地址由小向大增加,而数据从高位往低位放;

     所谓的小端模式是指:数据的低位保存在内存的低地址中,而数据的高位保存在内存的高地址中,这种存储模式将地址的高低和数据位权有效地结合起来,高地址部分权值高,低地址部分权值低,和我们的实际逻辑方法一致。
代码如下:

#include "stdafx.h"
#include<iostream>
using namespace std;
int checkCpu()
{
	union w
	{
		int a;
		char b;
	}c;
	c.a=1;
	return (c.b==1);
}
int _tmain(int argc, _TCHAR* argv[])
{
	cout<<checkCpu()<<endl;//1:说明是小端模式

	system("pause");
	return 0;
}

总结:
其实大小端的问题很简单的,就是因为数据在同样的内存可以有两种存储模式。
简单记住:低低小,低高大。
也就是说:低位数据存入低地址小端;低位数据存入高地址大端。

字节对齐

看例子吧:

// Test.cpp : 定义控制台应用程序的入口点。
#include "stdafx.h"
#include<iostream>
using namespace std;
class A
{
public:
	int i;
};
class B
{
public:
	char ch;
};
class C
{
public:
	int i;
	short j;
};
class D
{
public:
	int i;
	short j;
	char ch;
};
class E
{
public:
	int i;
	int ii;
	short j;
	char ch;
	char chr;
};
class F
{
public:
	int i;
	int ii;
	int iii;
	short j;
	char ch;
	char chr;
};
class G
{
public:
	int i;
	int ii;
	short j;
	char ch;
	char chr;
	int iii;
};
class H
{
public:
	int i;
	int ii;
	char ch;
	char chr;
	int iii;
	short j;
};
class I
{
public:
	int i;
	char ch;
	int ii;
	char chr;
	int iii;
	short j;
};
class J
{
public:
	char ch;
	int i;
};
class K
{
public:
	int i;
	J j;
};
int _tmain(int argc, _TCHAR* argv[])
{
	cout<<"sizeof(int): "<<sizeof(int)<<endl;
	cout<<"sizeof(short): "<<sizeof(short)<<endl;
	cout<<"sizeof(char): "<<sizeof(char)<<endl;
	cout<<endl;
	cout<<"sizeof(A): "<<sizeof(A)<<endl;
	cout<<"sizeof(B): "<<sizeof(B)<<endl;
	cout<<"sizeof(C): "<<sizeof(C)<<endl;
	cout<<"sizeof(D): "<<sizeof(D)<<endl;
	cout<<"sizeof(E): "<<sizeof(E)<<endl;
	cout<<"sizeof(F): "<<sizeof(F)<<endl;
	cout<<"sizeof(G): "<<sizeof(G)<<endl;
	cout<<"sizeof(H): "<<sizeof(H)<<endl;
	cout<<"sizeof(I): "<<sizeof(I)<<endl;
	cout<<"sizeof(J): "<<sizeof(J)<<endl;
	cout<<"sizeof(K): "<<sizeof(K)<<endl;

	system("pause");
	return 0;
}

输出:




抱歉!评论已关闭.