• 【C/C++】结构体中使用变长数组问题分析


    1. 问题来源

    今天在结构体里面使用变长数组来封装消息体,运行程序时弹出如下错误:

    *** stack smashing detected ***: <unknown> terminated
    Aborted (core dumped)
    
    • 1
    • 2

    问题已经解决,由于源程序不方便截取,现在通过一个实例来复现问题。


    2. 问题复现

    2.1 初始程序

    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    
    typedef struct {
        int a;
        char body[];
    } msg_t;
    
    int main(void)
    {
        msg_t msg;
        char *pdu = "abcdefg";
        strcpy(msg.body,pdu);
        printf("msg body:%s\n",msg.body);
    
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    上述程序编译是没有问题的,但如果带变长数组的结构体换两种写法,会复现两种错误。


    2.2 独立变长数组复现

    typedef struct {
        char body[];
    } msg_t;
    
    • 1
    • 2
    • 3

    结构体中只有变长数组body[],无其他成员。编译错误如下:

    test.c:7:10: error: flexible array member in a struct with no named members
         char body[];
    
    • 1
    • 2

    这种情况在实际中并不会出现,如果只有一个成员,就没必要多一层结构体。


    2.3 变长数组置前复现

    typedef struct {
    	char body[];
    	int a;
    } msg_t;
    
    • 1
    • 2
    • 3
    • 4

    变长数组body[]不为结构最后一个成员。编译错误如下:

    test.c:7:10: error: flexible array member not at end of struct
         char body[];
    
    • 1
    • 2

    这种情况就是按照C99标准变长数组必须是结构体的最后一个成员。


    2.4 缓冲区溢出复现

    运行编译出的可执行程序,打印错误如下:

    msg body:abcdefg
    *** stack smashing detected ***: <unknown> terminated
    Aborted (core dumped)
    
    • 1
    • 2
    • 3

    这里是因为没有为变长数组body分配内存,检测到了缓冲区溢出,通过如下表达式分配内存:

    msg_t *msg= (msg_t*)malloc(sizeof(msg_t)+16*sizeof(char));
    
    • 1

    这样就为结构体指针msg分配了一块内存空间,程序变为:

    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    
    typedef struct {
        int a;
        char body[];
    } msg_t;
    
    int main(void)
    {
        msg_t *msg = (msg_t*)malloc(sizeof(msg_t)+16*sizeof(char));
        char *pdu = "abcdefg";
    
        strcpy(msg->body,pdu);
        printf("msg body:%s\n",msg->body);
        free(msg);
    
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    编译成功,运行结果正常:

    msg body:abcdefg
    
    • 1

    3. 结构体变长数组使用要点

    • 结构体中不能只有变长数组一个成员,同时变长数组必须为结构体最后一个成员。
    • 变长数组不占用结构体的存储空间,长度为0,数组名只是一个占位符。sizeof()计算结构体大小时,变长数组在其中长度为0。
    • 使用变长数组结构体时,用malloc()分配内存空间。使用完毕用free()可以直接释放整个结构体的空间。
  • 相关阅读:
    深度学习的数值问题
    端口探测详解
    关于 ‘cosylocal‘ 进程占满内存的问题
    window小技巧---------电脑自动开关机/电脑自动开机后打开应用/打开浏览器后自动响应某个页面并且f12
    STM32CubeIDE中 sprintf() 函数错误问题解决办法
    Gmail邮箱怎么获取授权码?熟悉一下
    软件考试学习笔记(希赛)
    前端和后端交互数据类型转换
    七大顶尖 C++ 开源构建系统
    Vue的生命周期快速入门
  • 原文地址:https://blog.csdn.net/NoBack7/article/details/125529483