大家好,我是杂烩君。 上篇文章分享几个实用的代码片段(第二弹)我们分享了一段代码: ![]() 有位读者在朋友圈评论我的文章:(type * )0不是指向空地址吗?(type*)0->member不是访问非法内存了吗?为什么不会出错? ![]() 这篇文章我们就来解释这个问题。 GET_MEMBER_SIZE分析首先,先来解释
虽然说这里用了 其实不是的,注意这里用到了
所有内存的开辟只有程序运行的时候才会在物理内存中开辟,即sizeof(((type*)0)->member)的操作不是等到程序运行期间计算的,而是在编译阶段就计算了,所以GET_MEMBER_SIZE宏定义并没有访问非法内存的操作。 进一步的,我们看看上面那个代码实例中,结构体成员的字节数是不是在编译阶段计算出的,编译出汇编文件:
![]() 这个汇编文件我们可能不全看懂所有指令,但大概知道如下三个指令的意思我们就大概可以知道这段汇编代码的意思了。
可以看到,从上到下,依次会把立即数1、1、2、4、3、12放到esi寄存器中。 为什么是这些立即数? 我们编译运行一下我们的程序: ![]() 可以看到,正好就是我们需要求的结构体各成员的大小及结构体的大小,所以GET_MEMBER_SIZE(type, member)是在编译阶段起作用的。 其实,GET_MEMBER_SIZE宏定义中的0只是看做一个随意给的地址,方便求成员的大小,如果写为0容易引起误解,不妨可以写为一个任意值,比如修改为100,也是可以计算出各结构体成员的大小的。 ![]() ![]() 最后,如果 ![]() 编译运行: ![]() |
|