• 【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()可以直接释放整个结构体的空间。
  • 相关阅读:
    共享办公室行业当前发展现状和未来发展前景
    HTTP协议报文格式
    十天学完基础数据结构-第三天(数组(Array))
    腾讯云4核8G服务器轻量和CVM可用来干什么?
    链式二叉树
    【Solution】一文学会微信扫码登录
    图解LeetCode——1224. 最大相等频率(难度:困难)
    tomcat启动配置java_home,启动网址等,点击startup.bat直接启动
    【Asp.net】Asp.net core中IIS配置注意事项
    初识设计模式 - 迭代器模式
  • 原文地址:https://blog.csdn.net/NoBack7/article/details/125529483