
首先,结构和功能参数
用作函数参数的结构可以分为传递值和传递指针.
1. 传递值时,将复制structure参数. 实际上,在函数主体中修改结构参数成员的值实际上是在修改调用参数的临时副本的成员的值,这不会影响调用参数. 在这种情况下,由于结构参数的复制,会影响程序空间和时间效率,因此基本上不使用此方法.
例如:
typedef struct tagSTUDENT {
字符名称[20];
年龄;
}学生;
没有乐趣(学生stu)
{
printf(“ stu.name =%s,stu.age =%d / n”,stu.name,stu.age);
}
2. 传递指针时,结构的第一个地址直接传递给函数体. 在函数主体中,结构成员由指针引用,这实际上会影响结构参数成员的值. 这种用法效率很高,并且经常使用.
例如:
typedef struct tagSTUDENT {
字符名称[20];
年龄;
}学生;
没有乐趣(学生* pStu)
{
printf(“ pStu-> name =%s,pStu-> age =%d / n”结构体,pStu-> name,pStu-> age);
}
第二,结构和函数的返回值
对于某些版本的C语言编译器,返回值只能是基本数据类型,例如int,char和指针,因此,作为组合数据类型的结构不能通过value返回. 在某些版本中,在C编译器中,可以直接返回结构变量,而在C ++中,也可以直接返回结构变量.
直接返回结构变量的示例如下;
typedef struct tagSTUDENT {
字符名称[20];
年龄;
}学生;

学生fun();
int _tmain(int argc,_TCHAR * argv [])
{
学生p = fun();
printf(“ p.name =%s”,p.name);
返回0;
}
学生fun()
{
学生stu;
stu.age = 18;
strcpy(stu.name,“ xiaoming”);
返回stu;
}
将结构作为指针返回的示例如下:
typedef struct tagSTUDENT {
字符名称[20];
年龄;
}学生;
学生* fun()
{
学生* p = malloc(sizeof(STUDENT));
p-> age = 18;
strcpy(p-> name,“ xiaoming”);
返回p;
}
关于结构,我再次看到了内核. 关于作业中作业的奇怪用法,我在Internet上找不到答案,但是我发现了我一直遇到的模糊对齐问题. 以下是重新发布的内容:
有人总结了对齐原理. 我现在在哪里可以看到它?我不记得了以下是以前人的经验参考(没有#pragma pack宏):
原理1.数据成员对齐规则: 结构(结构或联合)的数据成员,第一个数据成员放置在偏移量0处,将来每个数据成员存储的起始位置应从的大小开始. 该成员以整数倍开头(例如,在32位计算机上int是4字节,那么您需要以4的整数倍存储)

原理2.作为成员的结构: 如果结构中有某些结构成员,则应从内部最大元素大小的整数倍开始存储结构成员. (结构包含b中的结构b,char,int,double和其他元素,然后b应该以8的整数倍存储. )
原则3.完成工作: 结构的总大小(即sizeof的结果)必须是其最大成员的整数倍,并且应填补不足之处.
您如何理解这三个原则?我们通过以下示例来加深对示例的理解.
示例1: 结构{
短a1;
short a2;
short a3;
} A;
结构{
long a1;
short a2;
} B;
sizeof(A)= 6;这很容易理解,所有三个短裤均为2.
sizeof(B)= 8;这比预期的大2个字节吗?长为4,短为2,整体为8,因为原则3.
示例2: 结构A {
int a;
字符b;
short c;
};
结构B {
字符b;
int a;
short c;
};
sizeof(A)= 8; int是4,char是1,short是2,这里使用了原则1和原则3.
sizeof(B)= 12;是否超出预期范围?字符是1,整数是4,短整数是2,怎么可能是12?或原则1和原则3.
仔细研究为什么会这样,我们可以查看内存中的布局.
abc
A的内存布局: 1111,1 *,11

bac
B的内存布局: 1 ***,1111、11 **
其中,星号*表示填充字节. 在A中,为什么要在b之后添加一个字节?因为c短,所以它的起始位置必须是2的倍数,这是原则1. c后面没有补码,因为b和c恰好占据4个字节,并且A占用的整个空间是4的倍数,即是最大成员int类型的倍数,因此不需要补充.
B,b是char是1,并且在b之后添加3个字节,因为a is int是4,根据原理1,起始位置应为4的倍数,因此应在b之后添加3个字节. c之后添加两个字节. 根据原理3,整个B占用4的倍数. 不添加c后的空间,并且整个B空间为10,这不匹配,因此添加2个字节.
再看一个具有结构成员的结构示例:
示例3: 结构A {
int a;
双b;
浮点c;
};
结构B {
字符e [2];
int f;
双g;
短h;
结构A i;
};
sizeof(A)= 24;这很容易理解,int是4,double是8,float是4,总长度是8的倍数,整个A是24.
sizeof(B)= 48;看一下B的内存布局.
efghi
B的内存布局: 11 * *,1111,11111111,11 * * * * **,1111 * * * *,11111111,1111 * * * *
i实际上是A的内存布局. i的起始位置应该是24的倍数,因此我们需要在h之后填写. 明确B的内存布局,基本掌握相关结构的对齐方式.
以上是所有没有#pragma pack宏的情况. 如果有#pragmapack宏,则对齐将遵循宏定义. 例如,如果在上述结构之前添加#pragma pack(1),则内存布局将完全更改. sizeof(A)= 16; sizeof(B)= 32;
使用#pragma pack(1),内存将不再遵循原则1和原则3,而是按1个字节对齐. 是的,这不是没有内存对齐的理想世界吗?
abc
A的内存布局: 1111、11111111、1111
efghi
B内存布局: 11,1111,11111111,11,1111,11111111,1111
#pragma pack(2)的结果是什么? #pragma pack(4)?让每个人都自己思考,我相信没有问题.

还有一种常见的情况,其中结构包含位字段字段. 位字段成员不能单独使用sizeof值. C99规定可以将int,unsignedint和bool用作位字段类型,但是编译器几乎总是将其扩展为允许存在其他类型.
使用位字段的主要目的是压缩存储,一般规则是:
1)如果相邻位字段的类型相同,并且它们的位宽之和小于该类型的大小,则以下字段将存储在前一个字段的旁边,直到无法容纳它们为止;
2)如果相邻位字段的类型相同,但是它们的位宽之和大于该类型的大小,则以下字段将从新的存储单元开始,并且偏移量为类型大小的整数倍;
3)如果相邻位字段的类型不同,则每个编译器的具体实现方式也不同. VC6采用非压缩模式,Dev-C ++采用压缩模式;
4)如果非位字段散布在位字段之间,将不执行压缩;
5)整个结构的总大小是最宽的基本类型成员的大小的整数倍.
让我们看一个例子.
示例4: 结构A {
char f1: 3;
char f2: 4;
char f3: 5;
};
abc
A的内存布局: 111,1111 *,11111 * * *
位字段类型为char. 第一个字节只能容纳f1和f2,因此f2被压缩为第一个字节,而f3只能从下一个字节开始. 因此,sizeof(A)的结果为2.
示例5: 结构B {
char f1: 3;
短f2: 4;
char f3: 5;
};
由于相邻位字段的类型不同,在VC6中它的sizeof为6,在Dev-C ++中它的大小为2.
示例6: struct C {
char f1: 3;
char f2;
char f3: 5;
};
非位字段散布在其中,不会进行压缩,并且在VC6和Dev-C ++中获得的大小为3.
考虑一个问题,为什么要设计内存对齐方式?如果架构未对齐,则成员将被一个接一个地存储,显然对齐会浪费空间. 那么为什么要使用对齐方式呢?架构的对齐与不对齐是时间与空间之间的权衡. 对齐可节省时间. 假设架构的字长为w结构体,则还假定宽度为w的数据的处理在该架构上是最频繁且最重要的. 优先考虑其设计以提高w位数据操作的效率. 如果您有兴趣,可以在Google上搜索,其他人可以向您解释,这是很多事实.
最后,顺便说一句,在设计结构时,通常会遵循以下习惯: 将字体放在前面的空间很小,而字体放在后面的空间大,这样可以节省一些对齐空间.
本文来自电脑杂谈,转载请注明本文网址:
http://www.pc-fly.com/a/jisuanjixue/article-251883-1.html
它们敢来