C语言结构体的内存分布和结构体指针

在公司的代码中看到这样一段:
头文件中:

#ifndef cpu_info_h__
#define cpu_info_h__
//...
     typedef struct sys_cpu_usage_* sys_cpu_usage_handle;
	 sys_cpu_usage_handle create_cpu_usage_calculator();
// ...
#endif //  cpu_info_h__

结构体 sys_cpu_usage_ 在对应的源文件中才进行了定义,而对应的源文件会编译成共享库的形式。于是好奇当我自己编程时,包含了此头文件的源码为何在编译时不被编译器报错,因为编译器不知道 sys_cpu_usage_ 是个什么东西。

实验1:
#include <stdio.h>
typedef struct Test
{
        int a;
        int b;
}Test_t;
int main()
{
         struct mystruct * hdl = calloc(1,8);
        Test_t test = {1,2};
        hdl = &test;
        printf("hdl->a = %d\nhdl->b = %d\n", ((Test_t*)hdl)->a, ((Test_t *)hdl)->b);
}

最后成功的输出了a、b的值。
说明在声明hdl这个指针时,编译器只需要知道它是个指针,而不需要知道它指向的是什么类型,比如声明一个(void *)也是同样的效果。
只有当需要取结构体中的值时,编译器才会去寻找该结构体的定义,以此来对该结构进行“使用”。
如果在未定义结构体的情况下对结构体内数据进行访问,会报以下错误:
error: dereferencing pointer to incomplete type

说明该结构体类型未定义,但尝试去访问结构体内部的事物。编译器会报错。

实验2:
#include <stdio.h>
typedef struct Test
{
        int a;
        int b;
}Test_t;
int main()
{
         struct mystruct * hdl = calloc(1,2);
        Test_t test = {1,2};
        memcpy(hdl,&test,8);
        printf("sizeof(Test_t) = %d\nhdl->a = %d\nhdl->b = %d\n", sizeof(Test_t), ((Test_t*)hdl)->a, ((Test_t *)hdl)->b);
}

而以上的代码会生成如下的结果。

[root@masternode sysinfo]# ./test1
sizeof(Test_t) = 8
hdl->a = 1
hdl->b = 2

只为指针hdl申请了2字节的内存,但是把大小为8字节的变量test拷贝过去后,结构体仍能访问到全部的数值,此时发生了内存越界。

实验3:
#include <stdio.h>
typedef struct Test
{
        int a1;
        int a2;
        int a3;
        int a4;
        int a5;
        int a6;
        int a7;
        int a8;
        int a9;
}Test_t;
int main()
{
        struct mystruct * hdl = calloc(1,2);
        Test_t test = {1,2,3,4,5,6,7,8,9};
        memcpy(hdl,&test,36);
        printf("hdl = %d\nhdl->a1 = %d\nhdl->a9 = %d\n", hdl, ((Test_t*)hdl)->a1, ((Test_t *)hdl)->a9);
        Test_t * hdl_next = calloc(1,36);
        memcpy(hdl_next,&test,36);
        printf("hdl_next = %d\nhdl->a1 = %d\nhdl->a9 = %d\n", hdl_next, ((Test_t *)hdl)->a1, ((Test_t *)hdl)->a9);
}

输出如下:

[root@masternode sysinfo]# ./test1
hdl = 30826512
hdl->a1 = 1
hdl->a9 = 9
hdl_next = 30826544
hdl->a1 = 1
hdl->a9 = 1

可以看到结构体Test_t有9个int类型内容,也就是36字节的大小。可以认为calloc分配堆空间时,最小分配单位为32字节,也就是hdl_next比hdl多32。
虽然只为hdl申请了2字节的堆内存,但是实际上给了32字节,那么当memcpy时,32字节范围内的内容都不会被hdl_next污染。也就是说虽然hdl发生了越界(2字节存36字节),但前面的32字节都不会被hdl_next覆盖。
从32字节开始,hdl_next也存了自己的数据,hdl的a9就被hdl_next的a1覆盖掉了。
所以可以看到,在没有hdl_next时,hdl即使越界了,也没有被污染,它可以访问到正确的值。但是为hdl_next分配堆时,因为hdl的calloc只要了2字节,编译器认为32字节后的空间可以拿来分配(并不管上面是不是有数值),于是分配给了hdl_next,hdl_next赋值之后,就会把hdl后4个字节覆盖掉。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值