c语言

来源:互联网 发布:独立游戏开发者 知乎 编辑:程序博客网 时间:2024/06/05 18:08

一:static的用法定义:静态变量,静态成员,静态成员函数。静态变量的定义static 数据类型 变量。在类的数据成员前面加上static就成为静态成员。静态成员的定义 类里面类型 类名::静态成员名同时在右边可以赋初值。在类外定义静态数据成员不需要加static限定词。静态成员的访问类名::静态成员名或对象名.静态成员名。在类成员函数前面加上static就成为静态成员函数。静态函数的调用类名::静态成员函数名(参数表)或静态函数的调用类名.静态成员函数名(参数表)。

inline的定义:用法:inline函数,在函数定义或申明时在函数返回值类型前加上inline就成为内联函数了。内联函数不需要进行参数传递,执行效率更高,其不足是占用更多的存储空间,且函数只能是简单的小程序,出现循环语句,switch,goto等复杂的函数不能是内联函数。

extern的定义用法:主要用来声明外部变量,如果在定义点之前的函数引用该外部变量,则在引用之前需加extern进行外部变量申明。用法extern 变量名。需在调用函数后面对外部变量赋初值。

二:多文件开发的好处:

1便于复用代码。通用性强的重复的功能只要写一遍就可以了,下次用在其他程序上只要修改很小的一部分或者不修改。

2便于多人协作

3便于维护和修改,如果某块有问题,只需对那块模块进行修改即可。

.h文件和.c文件的异同

函数定义要放在.c中

函数的申明放在.h中


----------------------------------------------------------------第二次作业----------------------------------------------------------------------------------------------------------

a. 熟悉printf,scanf、malloc、realloc、calloc(与c++的new的区别)的各种用法

printf的作用:输出,其中“”内的为原样输出,除了%d,%f之类的,“”为表示要输出值的表达式或变量

scanf的作用:输入。从键盘都入到内存中

malloc的作用:动态初始分配一段内存空间

realloc的作用:再分配一段内存空间

calloc的作用:在内存的动态存储区中分配n个长度为size的连续空间,函数返回一个指向分配起始地址的指针

realloc,calloc与new的区别:(1)new不需要进行类型转换,它能自动返回正确的指针类型。(2)new可以对分配的内存进行初始化(3)new能够自动计算要分配内存的大小,不必用sizeof函数计算所要分配的内存字节数.new只能用于c++中。realloc和calloc的区别主要是前者不能初始化所分配的内存空间,后者能。如果由malloc函数分配的内存空间,原来没有被使用过,则其中的每一位可能都是零,如果这部分内存曾经被分配过,则其中可能遗留各种各样的数据。即开始时内存空间没有被重新分配,能正常进行,但经过一段时间,内存空间还未被重新分配时可能会出现问题。使用calloc函数将分配的内存空间中的每一位都初始化为零,无论是字符型,字符串,元素都被初始化0,指针则会被初始化为空指针。

 b. 熟悉什么叫编译屏障、内存对齐

编译屏障:

内存对齐:

结构体的内存布局依赖于CPU、操作系统、编译器及编译时的对齐选项。结构体内部成员的对齐要求,结构体本身的对齐要求。最重要的有三点

(1)成员对齐。对于结构体内部成员,通常会有这样的规定:各成员变量存放的起始地址相对于结构的起始地址的偏移量必须为该变量的类型所占用的字节数的倍数。但是也可以看到,有时候某些字段如果严格按照大小紧密排列,根本无法达到这样的目的,因此有时候必须进行padding。各成员变量在存放的时候根据在结构中出现的顺序依次申请空间,同时按照上面的对齐方式调整位置,空缺的字节编译器会自动填充也就是padding。

(2)然后,还要考虑整个结构体的对齐需求。ANSI C标准规定结构体类型的对齐要求不能比它所有字段中要求最严格的那个宽松,可以更严格。实际上要求结构体至少是其中的那个最大的元素大小的整数倍。因为有时候我们使用的是结构体数组,所以结构体的大小还得保证结构体数组中各个结构体满足对齐要求,同时独立的结构体与结构体数组中单个结构体的大小应当是一致的。

(3)编译器的对齐指令。VC 中提供了#pragma pack(n)来设定变量以n字节对齐方式。n字节对齐就是说变量存放的起始地址的偏移量有两种情况:第一、如果n大于等于该变量所占用的字节数,那么偏移量必须满足默认的对齐方式,第二、如果n小于该变量的类型所占用的字节数,那么偏移量为n的倍数,不用满足默认的对齐方式。结构的总大小也有个约束条件,分下面两种情况:如果n大于所有成员变量类型所占用的字节数,那么结构的总大小必须为占用空间最大的变量占用的空间数的倍数。

规则http://bigwhite.blogbus.com/logs/1347304.html

(1)数据成员对齐规则:结构(struct)(或联合(union))的数据成员,第一个数据成员放在offset为0的地方,以后每个数据成员的对齐按照#pragma pack指定的数值和这个数据成员自身长度中,比较小的那个进行。

(2)结构(或联合)的整体对齐规则:在数据成员完成各自对齐之后,结构(或联合)本身也要进行对齐,对齐将按照#pragma pack指定的数值和结构(或联合)最大数据成员长度中,比较小的那个进行。

(3)结合1、2推断:当#pragma pack的n值等于或超过所有数据成员长度的时候,这个n值的大小将不产生任何效果。

总结一下:

成员对齐有一个重要的条件,即每个成员分别对齐.即每个成员按自己的方式对齐.如果有#pragma pack(8),它虽然指定了按8字节对齐,但并不是所有的成员都是以8字节对齐.其对齐的规则是,每个成员按类型的对齐参数(通常是这个类型的大小)和指定对齐参数(这里是8字节)中较小的一个对齐.并且结构的长度必须为所用过的所有对齐参数的整数倍,不够就补空字节.也就是说对齐后的长度必须是成员中最大的对齐参数的整数倍,这样在处理数组时可以保证每一项都边界对齐。实际上根据这些规则安排整个的内存布局的算法很简单,假设起始地址为0,开始安放第1个成员,然后找到下一个成员可以安放的起始位置,首先这个位置肯定在第一个成员之外,其次满足那些对齐因素。找到满足这两个条件的第一个位置即可。然后再考虑下一个成员,逐次进行下去。最后再考虑整个结构体的对齐因素,确定整个结构体的结束位置,这个位置的下个位置也就是下一个结构体的开始位置,保证它能够满足对齐。

比如:
struct MyStruct
{
char dda;
double dda1;  
int type
};

(简单说明)
struct MyStruct
{
char dda;//偏移量为0,满足对齐方式,dda占用1个字节;
double dda1;//下一个可用的地址的偏移量为1,不是sizeof(double)=8
             //的倍数,需要补足7个字节才能使偏移量变为8(满足对齐
             //方式),因此VC自动填充7个字节,dda1存放在偏移量为8
             //的地址上,它占用8个字节。
int type;//下一个可用的地址的偏移量为16,是sizeof(int)=4的倍
           //数,满足int的对齐方式,所以不需要VC自动填充,type存
           //放在偏移量为16的地址上,它占用4个字节。
};//所有成员变量都分配了空间,空间总的大小为1+7+8+4=20,不是结构
   //的节边界数(即结构中占用最大空间的类型所占用的字节数sizeof
   //(double)=8)的倍数,所以需要填充4个字节,以满足结构的大小为
   //sizeof(double)=8的倍数。
所以该结构总的大小为:sizeof(MyStruc)为1+7+8+4+4=24。其中总的有7+4=11个字节是VC自动填充的,没有放任何有意义的东西。




       规则http://bigwhite.blogbus.com/logs/1347304.html
1、数据成员对齐规则:结构(struct)(或联合(union))的数据成员,第一个数据成员放在offset为0的地方,以后每个数据成员的对齐按照#pragma pack指定的数值和这个数据成员自身长度中,比较小的那个进行。
2、结构(或联合)的整体对齐规则:在数据成员完成各自对齐之后,结构(或联合)本身也要进行对齐,对齐将按照#pragma pack指定的数值和结构(或联合)最大数据成员长度中,比较小的那个进行。
3、结合1、2推断:当#pragma pack的n值等于或超过所有数据成员长度的时候,这个n值的大小将不产生任何效果。

总结一下:
成员对齐有一个重要的条件,即每个成员分别对齐.即每个成员按自己的方式对齐.如果有#pragma pack(8),它虽然指定了按8字节对齐,但并不是所有的成员都是以8字节对齐.其对齐的规则是,每个成员按类型的对齐参数(通常是这个类型的大小)和指定对齐参数(这里是8字节)中较小的一个对齐.并且结构的长度必须为所用过的所有对齐参数的整数倍,不够就补空字节.也就是说对齐后的长度必须是成员中最大的对齐参数的整数倍,这样在处理数组时可以保证每一项都边界对齐。实际上根据这些规则安排整个的内存布局的算法很简单,假设起始地址为0,开始安放第1个成员,然后找到下一个成员可以安放的起始位置,首先这个位置肯定在第一个成员之外,其次满足那些对齐因素。找到满足这两个条件的第一个位置即可。然后再考虑下一个成员,逐次进行下去。最后再考虑整个结构体的对齐因素,确定整个结构体的结束位置,这个位置的下个位置也就是下一个结构体的开始位置,保证它能够满足对齐。

比如:
struct MyStruct
{
char dda;
double dda1;  
int type
};

(简单说明)
struct MyStruct
{
char dda;//偏移量为0,满足对齐方式,dda占用1个字节;
double dda1;//下一个可用的地址的偏移量为1,不是sizeof(double)=8
             //的倍数,需要补足7个字节才能使偏移量变为8(满足对齐
             //方式),因此VC自动填充7个字节,dda1存放在偏移量为8
             //的地址上,它占用8个字节。
int type;//下一个可用的地址的偏移量为16,是sizeof(int)=4的倍
           //数,满足int的对齐方式,所以不需要VC自动填充,type存
           //放在偏移量为16的地址上,它占用4个字节。
};//所有成员变量都分配了空间,空间总的大小为1+7+8+4=20,不是结构
   //的节边界数(即结构中占用最大空间的类型所占用的字节数sizeof
   //(double)=8)的倍数,所以需要填充4个字节,以满足结构的大小为
   //sizeof(double)=8的倍数。
所以该结构总的大小为:sizeof(MyStruc)为1+7+8+4+4=24。其中总的有7+4=11个字节是VC自动填充的,没有放任何有意义的东西。

0 0
原创粉丝点击