【原创】关于C语言的变长结构体(内嵌柔性数组):C Struct Hack

blogdaren 2021-01-17 抢沙发 76人次

问题背景:

在PHP内核的字符串实现源码中我们发现了这么一个结构体如下:

struct _zend_string {                                                                                                                                                  
    zend_refcounted_h gc; 
    zend_ulong        h;                /* hash value */
    size_t            len;
    char              val[1];
};
也就是说PHP的字符串底层实现并没有使用char *,而是使用了这么一个结构体,并且字符串的内存存储在val柔性数组当中,那么其中的 char val[1] 是什么意思呢? 

柔性数组:

C99关于变长结构体(学名:C Struct Hack)是这样描述的:

As a special case, the last element of a structure with more than one named member may have an incomplete array type; this is called a flexible array member.

问题解决:

根据C99描述可知 char val[1] 是柔性数组的用法,事实上字符串分配内存空间时是这样的: malloc(sizeof(zend_string) + 字符串长度),也就是会多分配出一些内存,而多出来的这部分内存的的起始位置正好是val,如此我们就能直接存储字符串内容啦;另外注意val[1]并不是表示只能存储一个字节,而使用val[1]而不使用val[0]的原因则是多出来这么一个字节用于存储字符串末尾的结束符'\0'.

问题补充:

1、柔性数组只能是变长结构体的最后一个成员;

2、变长结构体必须至少包含2个成员;

源码展示:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

struct mystring
{
    int len;
    char val[1];
};

typedef struct mystring Mystring;

Mystring *createDynamicString(char *str, size_t len);

int main()
{
    Mystring *p;
    p = createDynamicString("baidu", strlen("baidu"));
    printf("%d-%s\n", p->len, p->val);
    free(p);
    p = createDynamicString("google", strlen("google"));
    printf("%d-%s\n", p->len, p->val);
    free(p);

    return 0;
}

Mystring *createDynamicString(char *str, size_t len)
{
    Mystring *ptr;
    ptr = (Mystring *)malloc(sizeof(Mystring) + len + 1);

    if(ptr == NULL) return NULL;
    
    ptr->len = len;
    printf("%d\n", sizeof(Mystring) + len + 1);
    memcpy(ptr->val, str, len);

    return ptr;
}

版权声明:除非注明,本文由( blogdaren )原创,转载请保留文章出处。

本文链接:【原创】关于C语言的变长结构体(内嵌柔性数组):C Struct Hack

发表评论:

您的昵称:
电子邮件:
个人主页:

Free Web Hosting