勇哥注:
指针练习好了,能解决90%的驱动开发时遇到的各种问题。
#include<stdio.h> typedef void(*p_fun)(int i, int j); struct st { int i; int j; int b; p_fun p_fun1; }; void fun(int i, int j) { printf("fun%d %d\n", i, j); } int main() { struct st st_ = { 0 }; st_.i = 1; st_.j = 2; st_.p_fun1 = fun; st_.p_fun1(1, 2); //fun1 2 printf("%p %p\n", st_.p_fun1, &st_.p_fun1); //00007FF668281334 000000496FF2F5A8 struct st* pst_; pst_ = &st_; printf("%d %d\n", st_.i, st_.j); //1 2 int* p_int = (int*)pst_; printf("+0 %d %p\n", *p_int, p_int); // 1 0000001B7CB2F4F8 //*p_int=1; p_int += 1; printf("+1 %d %p\n", *p_int, p_int); //+1 2 0000001B7CB2F4FC //*p_int=2; p_int += 1; *p_int = 3; printf("+1 %d %p\n", *p_int, p_int); //+1 3 0000001B7CB2F500 p_int += 1; printf("+1 %d %p\n", *p_int, p_int); //+1 0 0000001B7CB2F504 p_int += 1; printf("+1 %p %p %p\n", *p_int, p_int, *(long long int*)p_int); //+1 0000000068281334 000000496FF2F5A8 00007FF668281334 p_fun p =(p_fun)(*(long long int*)p_int); printf("%p\n",p); //00007FF65AF91334 p(1, 2); //fun1 2 (*(p_fun*)p_int)(2, 3); //fun2 3 printf("%lld\n", sizeof(struct st)); //24 return 0; }
结果:
勇哥解释一下:
(1)struct st st_ = { 0 };
这个是结构体的初始化,也称为聚合初始化或列表初始化。
i,j,b初始化为int的缺省0,p_fun1实始化为nullptr,也就是指向地址为0的指针。
(2)如果结构体的指针不赋值会怎么样呢
就像下面这样注释掉指针的赋值。
struct st st_ = { 0 }; st_.i = 1; st_.j = 2; //st_.p_fun1 = fun; st_.p_fun1(1, 2); printf("%p %p\n", st_.p_fun1, &st_.p_fun1);
这样的话,你会使用指向零的指针,根据编译器不同报的错误不同。
对于vs2022会报下面的错误。
对于macos下的c++编译器来说,报的是:
segmentation fault 段错误。
这种错误在内核里经常发生。
(3)代码:printf("%p %p\n", st_.p_fun1, &st_.p_fun1);
%p是格式符,表示 输出指针类型,%d就是输出整数类型
&是地址符。
st_.p_fun1输出的是st_.p_fun1指针内容(即fun函数的地址),&st_.p_fun1输出的是指针变量st_.p_fun1的地址(任何变量都有自己的地址,包括简单类型变量、数据变量、结构体变量)
(4)%d是输出整数类型
struct st* pst_; pst_ = &st_; printf("%d %d\n", st_.i, st_.j);
结果是: 1 2
(5) 下面代码中,故意把pst_强行转为int*
然后用地址+1的方式,想取到st结构体的第4个元素。
这里值的注意的是,为什么需要+1四次才可以取到第4个元素。
原因是st的这第4个元素是函数指针,它占8个字节。而前面3个元素都是int,只占4个字节。
指针+1就等于按4个字节来向前移动。
int* p_int = (int*)pst_; printf("+0 %d %p\n", *p_int, p_int); // 1 0000001B7CB2F4F8 p_int += 1; printf("+1 %d %p\n", *p_int, p_int); //+1 2 0000001B7CB2F4FC p_int += 1; *p_int = 3; printf("+1 %d %p\n", *p_int, p_int); //+1 3 0000001B7CB2F500 p_int += 1; printf("+1 %d %p\n", *p_int, p_int); //+1 0 0000001B7CB2F504 p_int += 1; printf("+1 %p %p %p\n", *p_int, p_int, *(long long int*)p_int); //+1 0000000068281334 000000496FF2F5A8 00007FF668281334
long long int* 这个是标准C定的。就是64位int.
如果不转64位,00007FF668281334就会显示为0000000068281334,即精度丢失了32位。
(6)printf("%lld\n", sizeof(struct st));
为啥结果是24,而不是4+4+4+8=20字节?
原因是结构体的大小并不是按所有元素数据类型占的字节的总数这么算的。
必须要做字节边界对齐,这样内存读写效率才高。
所以结果是24,而不是20。

