问题背景:
在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 mayhave 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
#include
#include
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;
}