结构体的内存结构以及位域的认识

来源:互联网 发布:软件项目 文档 编辑:程序博客网 时间:2024/05/17 08:38
内存对齐:
        内存对齐应该是编译器管辖范围。编译器为程序中的每个数据单元安排在适当的位置上。但是C语言的一个特点就是太灵活,太强大,它允许你干预内存对齐
内存对其原因:
1、平台原因(移植原因):不是所有的硬件平台都能访问任意地址上的任意数据的;某些硬件平台只能在某些地址处取某些特定类型的数据,否则抛出硬件异常。
2、性能原因:数据结构(尤其是栈)应该尽可能地在自然边界上对齐。原因在于,为了访问未对齐的内存,处理器需要作两次内存访问;而对齐的内存访问仅需要一次访问。

内存对齐的规定:

1.数据成员对齐规则:结构(struct或联合union)的数据成员,第一个数据成员放在offset0的地方,以后每个数据成员存储的起始位置要从该成员自身大小的整数倍开始(比如int32位机为4字节,则要从4的整数倍地址开始存储)。

编译器在给结构体开辟空间时,首先找到结构体中最宽的基本数据类型,然后寻找内存地址能被该基本数据类型所整除的位置,作为结构体的首地址。将这个最宽的基本数据类型的大小作为上面介绍的对齐数。

 

2.结构体作为成员:如果一个结构里有某些结构体成员,则结构体成员要从其内部最大元素大小的整数倍地址开始存储。(struct a里存有struct bb里有charintdouble等元素,那b应该从8的整数倍开始存储。)

为结构体的一个成员开辟空间之前,编译器首先检查预开辟空间的首地址相对于结构体首地址的偏移是否是本成员的整数倍,若是,则存放本成员,反之,则在本成员和上一个成员之间填充一定的字节,以达到整数倍的要求,也就是将预开辟空间的首地址后移几个字节。

 

3.结构体成员相对首地址偏移量必须是成员大小的整数倍,也就是内存对齐。


4.结构体总大小必须是对齐模数的整数倍,举个例子,你最后加出来的值为30,但是你得对齐模数是8,这时候你就要补充两个字节,让结构体大小为32.


5.结构体的对齐模数其实还是自定义的 具体的格式就是我这样:

#pragma back(需要的对其模数)

对齐方式按照宏的定义来,比如在结构体前加#pragma pack(1),内存的布局就会完全改变,
有了#pragma pack(1),内存不会再遵循以上原则,按1字节对齐


下表是常见类型的对齐模数:

 

例:struct A{
       int a;
       double b;
      float c;
      };

     struct B{
     char e[2];
     int f;
     double g; 
     short h;
     struct A i;
     };

sizeof(A) = 24;
这个比较好理解,int4double8float4,总长为8的倍数,补齐,所以整个A24
sizeof(B) = 48;

位域:

位域是指信息在存储时,并不需要占用一个完整的字节, 而只需占几个或一个二进制位。例如在存放一个开关量时,只有01两种状态, 用一位二进位即可。为了节省存储空间,并使处理简便,C语言又提供了一种数据结构,称为位域位段。所谓位域是把一个字节中的二进位划分为几 个不同的区域, 并说明每个区域的位数。每个域有一个域名,允许在程序中按域名进行操作。这样就可以把几个不同的对象用一个字节的二进制位域来表示。

位域存储要求:
1. 一个位域必须存储在同一个字节中,不能跨两个字节。如一个字节所剩空间不够存放另一位域时,应从下一单元起存放该位域。也可以有意使某位域从下一单元开始。
2. 由于位域不允许跨两个字节,因此位域的长度不能大于一个字节的长度,也就是说不能
超过8位二进位。
3. 位域可以无位域名,这时它只用来作填充或调整位置。无名的位域是不能使用的。
位域的使用:
位域的使用和结构成员的使用相同,其一般形式为: 位域变量名·位域名 位域允许用各种格式输出。
实现1+2+3...+n,要求不能使用乘除法、循环、条件判断、选择相关的关键字。

利用new运算符开辟空间时,调用构造函数;静态成员为类的每个成员所共有;

#include<iostream>

using namespace std;

class Sum

{

public:

   Sum()//1.非静态成员函数内可以使用静态成员变量,调用静态成员函数

   {

       _n++;

       _sum+=_n;

   }

   static int sum()

   {

       return _sum;

   }

private:

   int c;

   static int _n;

   static int _sum;

};

//2.类的静态成员必须要在类外进行初始化 [类型 类名::变量名=初始值]

int Sum::_n=0;

int Sum::_sum=0;

int main()

{

   Sum* s=new Sum[100];

   cout<<Sum::sum()<<endl;

   delete[] s;

   return 0;

}


实现一个Add函数,让两个数相加,但是不能使用+-*/等四则运算符。ps:也不能用++--等

#include <iostream>

#include <Windows.h>

using namespace std;

int Add(int& num1,
int& num2)

{

            if (num1 == 0)

            {

                         return num2;

            }

            if (num2 == 0)

            {

                         return num1;

            }

            if (num1 == 0 && num2 == 0)

            {

                         return 0;

            }

            int yyr = num1^num2;

            int tty = (num1&num2) << 1;

            return Add(yyr, tty);

}

int main()

{

            int num1 = 6;

            int num2 = 6660;

            int ggy = Add(num1, num2);

            cout <<"两个数的为和:"<< ggy << endl;

            system("pause");

            return 0;

}





 














原创粉丝点击