C解析:结构体
内存对齐:
平台原因:不是所有的硬件平台都能访问任意地址上的任意数据。
性能原因:如果数据放在未对齐的内存空间中,则处理器访问变量时需要做两次内存访问。
内存对齐的具体规则如下:
1、结构体各个成员变量的内存空间首地址必须是“对齐系数”和“变量实际长度”中较小者的整数倍。
2、结构体本身也需要对齐,结构体占用的总大小应该为“对齐系数”和“最大数据成员长度”中较小者的整数倍。
struct data_test {
char a;
short b;
char c[2];
double d;
char e;
int f;
char g
}data;
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
由于结构体本身必须满足4 [因为 4 < sizeof(doubule d) 所以4字节对齐] 的整数倍,因此实际占用空间为28字节。
注意:通过优化结构体成员的定义顺序,在同样满足内存对齐的要求下,可以大大地减少内存浪费。
类型与变量:
range是struct _Range 类型的结构体变量。
struct _Range{
const int min;
const int max;
}range;
- 1
- 2
- 3
- 4
如果在结构体定义前添加typedef,range就变成了结构体的类型。习惯类型名的首地址大写,变量名的首地址小写,这里也可以 直接省掉类型名_Range。
有了Range类型,即可同时定义一个Range类型的变量range和一个指向Range*类型的指针变量pRange.
typedef struct{
const int min;
const int max;
}Range;
- 1
- 2
- 3
- 4
首先结构体告诉编译器是如何表示数据的,但它并未让编译器为数据分配空间。
初始化:
define newRangeCheck(min, max) {(min), (max)}
Range range = newRangeCheck(0, 9);
- 1
- 2
- 3
相当于:
range.min = 0; range.max = 9;
- 1
接口与实现:
传递结构体成员,传递结构体,传递结构体的地址
struct MyStruct{
int array[10];
}st;
- 1
- 2
- 3
显然只要将结构体的地址(int*)&st作为形参。
下面还是以范围校验器为例,定义一个指向结构体的指针变量pRange,其初始化、赋值与普通指针变量是一样的:
Range *pRange = ⦥
- 1
和数组不一样,结构体名并不是结构体的地址,因此要在结构体名前加上&。
range.min == (*pRange).min == pRange -> min
range.max == (*pRange).max == pRange -> max
- 1
- 2
用函数指针调用
根据依赖倒置原则,最好的方法是用函数指针隔离变化。
typedef bool (*const Validate)(void *pData, int value);
- 1
Validate validate = validateRange;
validate(&range, 8);
- 1
- 2
3 bool validateRange(void *pData, int value)
4 {
5 Range *pRange = (Range *)pData;
6 return pRange -> min <= value && value <= pRange -> max;
7 }
- 1
- 2
- 3
- 4
- 5
内置函数指针:方法
1 typedef struct _RangeValidator{
2 bool (*const RangeValidate)(struct _RangeValidator *pThis, int value);
3 const int min;
4 const int max;
5 }RangeValidator;
6
7 RangeValidator rangeValidator;
- 1
- 2
- 3
- 4
- 5
- 6
- 7
接口函数:
1 bool validateRange(struct _RangeValidator *pThis, int value)
2 {
3 return pThis -> min <= value && value <= pThis -> max;
4 }
- 1
- 2
- 3
- 4
可以将RangeValidate泛化成一般的函数指针类型Validate,由于每个函数都有一个指向当前对象的pThis指针,因此特殊的结构体类型struct_RangeValidator* 被泛化为void*类型,即可接受任何类型数据的实参。
1 typedef bool(*const Validate)(void *pThis, int value);
2 typedef struct{
3 Validate validate;
4 const int min;
5 const int max;
6 }RangeValidator;
- 1
- 2
- 3
- 4
- 5
- 6
接口函数:
3 bool validateRange(void *pThis, int value)
4 {
5 RangeValidator *pRangeValidator = (RangeValidator *)pThis;
6 return pRangeValidator -> min <= value && value <= pRangeValidator -> max;
7 }
- 1
- 2
- 3
- 4
- 5
初始化:
define newRangeValidator(min, max) {(validateRange), (min), (max)}
RangeValidator rangeValidator = newRangeValidator(0, 9);
- 1
- 2
- 3
定义指针:
void * pValidator = &rangeValidator;
- 1
函数调用:
前提是pValidator指向来了确定的结构体类型。
(RangeValidator *)pValidator -> validate(pValidator, 8);
- 1
如果pValidator将指向未知的校验器:
虽然pValidator与&rangeValidator.validate的类型不一样,但他们的值相等,因此可以利用这一特性获取validateRange()函数的地址。
Validate validate = *((Validate *)pValidator);
- 1
其调用形式如下:
validate(pValidator, 8);
- 1
1 bool rangeCheck(void *pValidator, int value)
2 {
3 Validate validate = *((Validate *)pValidator);
4 return validate(pValidator, value);
5 }
- 1
- 2
- 3
- 4
- 5
嵌套结构体
结构体数组
1 typedef struct CmdEntry{
2 void (*pfuncmd)();
3 char cHelp[64];
4 }CmdEntry;
- 1
- 2
- 3
- 4
static CmdEntry cmdArray[10] = {}
- 1
CmdEntry *pCmdEntry = &cmdArray[0]; // pCmdEntry->cHelp 即是cmdArray[0].cHelp
CmdEntry *pCmdEntry = cmdArray;
- 1
- 2
那么*pCmdEntry=cmdArray[0]
cmdArray[0].cHelp = (*pCmdEntry).cHelp
- 1
获取相应函数的入口地址:
cmdArray[0].pfuncmd = &CreateFile;
- 1
调用:
cmdArray[0].pfuncmd();
- 1
文章来源: xuesong.blog.csdn.net,作者:内核笔记,版权归原作者所有,如需转载,请联系作者。
原文链接:xuesong.blog.csdn.net/article/details/79200307