结构体大小计算
计算结构体大小的规则:
- 每一个成员的偏移量都必须是该成员的倍数。
- 结构体的大小必须是该结构体字节数最大成员的倍数。
先来说说什么是偏移量,某个成员的实际地址和结构体首地址之间的距离
struct data {
int a;
char b;
int c;
}
- 因为 a 为首地址,因此偏移量为 0
- 同时 int a 在内存中占 4 个字节,也就是是 b 的偏移量;由于 4 是 1 的整数倍,因此不用填充
- c 的偏移量为 4 + 1 = 5, 5 不是 4 的整数倍,需要加 3,于是 b 后面加了 3 个字节
- 最后来看看第二条规则,整个结构体中,int 占用内存最多,整个结构体大小为 4 + 1 + 3(填充字节) + 4 = 12 个字节,为 4 的倍数,因此结构体的大小为 12
之所以讲这个,是因为这关系到内存对齐,程序必须是加载到内存才能执行,而 CPU 访问内存时加载数据不是一个字节一个字节的加载,那样的话效率太低,而是一块一块加载的,一块长度可以是 2、4、8、16 字节大小,因此内存对齐了,那么 CPU 只需一次性便可加载,以空间换时间,从而提高效率。
typdef
typedef 就是给类型取别名,别名一般出现在变量名的位置。
int number;
typedef int number;
下面的这个 number 就是 int 的别名,今后可以使用 number 来声明变量
number num;
而且如果今后 number 需要由 int 型改成 long 型也很简单,只需调整下声明方式
typedef long number;
说到这里,大伙应该也会想起 define 这个关键字,这个主要要用来声明宏的,当然了也可以做些简单类型声明
#define int number;
number num;
在预处理阶段,会把 number 替换成 int,再来看看下面的这个
#define int* ptr;
ptr a1,a2;
替换后变成
int* a1,a2;
a1 声明为 int 型指针,而 a2 却不是,显然没有达到整体声明的效果。
再回到一开始声明的结构体
struct data dt;
是不是每次都得写 struct data,那么使用 typedef 可以简化
typedef struct data {
int a;
char b;
int c;
} data;
data dt;
函数指针
C 语言中万物皆有内存地址,函数也不例外。先从简单的 int 型指针说起
int *a;
声明了一个 int 型的指针 a,a 存放的是 int 型的指针地址,在 64 位的系统中内存大小为 8 位。
#include <stdio.h>
int add(int, int);
int main(int argc,char *argv[])
{
int a=1;
int b=2;
printf("a+b=%d\n", add(a, b));
}
int add(int a, int b)
{
return a+b;
}
上述的 add 方法,在内存中也有地址,可以使用 typedef 来声明函数指针
typedef (*func)(int, int);
func 代表内存 add 的起始地址。
#include <stdio.h>
int add(int, int);
typedef (*func)(int, int);
int main(int argc,char *argv[])
{
int a=1;
int b=2;
func f1 = add;
func f2 = add;
printf("a+b=%d\n", f1(a, b));
printf("a+b=%d\n", (*f2)(a, b)); // ANSI C认为 f1 和 (*f2) 这两种形式等价
}
int add(int a, int b)
{
return a+b;
}