C語(yǔ)言沒(méi)有STL,缺乏對(duì)動(dòng)態(tài)長(zhǎng)度字符串功能的支持钻蹬;同時(shí)吼蚁,C使用'\0'判斷字符串的結(jié)尾,不具有二進(jìn)制安全性。然而在程序開(kāi)發(fā)時(shí)肝匆,我們可以通過(guò)自定義的方式粒蜈,實(shí)現(xiàn)簡(jiǎn)易的動(dòng)態(tài)長(zhǎng)度字符串功能。
動(dòng)態(tài)長(zhǎng)度字符串結(jié)構(gòu)定義如下:
struct DynamicBuffer
{
unsigned len; // 實(shí)際長(zhǎng)度
unsigned free; // 剩余可用空間大小
char data[0]; // 實(shí)際內(nèi)容
};
其中旗国,較為少見(jiàn)的是DynamicBuffer結(jié)構(gòu)中的最后一項(xiàng)——定義了長(zhǎng)度為0的字符數(shù)組枯怖。零長(zhǎng)數(shù)組是在GNU C中定義的一項(xiàng)功能:
Zero-length arrays are allowed in GNU C. They are very useful as the last element of a structure which is really a header for a variable-length object.
在其他環(huán)境中編譯含有零長(zhǎng)數(shù)組的代碼可能會(huì)導(dǎo)致編譯錯(cuò)誤。
在DynamicBuffer的定義中能曾,我們當(dāng)然也可以用char*來(lái)保存字符串?dāng)?shù)據(jù)度硝。但是,使用零長(zhǎng)數(shù)組代替數(shù)組指針具有以下優(yōu)勢(shì):
- 指針占用存儲(chǔ)空間寿冕;而零長(zhǎng)數(shù)組則不占用結(jié)構(gòu)體空間蕊程。
- 使用指針需要初始化,使用時(shí)需要間接尋址驼唱;零長(zhǎng)數(shù)組不需要初始化存捺,內(nèi)存地址和后面的元素地址相同,數(shù)組名可以直接當(dāng)作指針使用曙蒸。
程序測(cè)試用例如下:
#include <stdio.h>
#include <stdlib.h>
#define LENGTH 5
struct DynamicBuffer1
{
unsigned len;
unsigned free;
char *data;
}__attribute((packed));
struct DynamicBuffer2
{
unsigned len;
unsigned free;
char data[0];
}__attribute((packed));
int main()
{
struct DynamicBuffer1 *b1;
struct DynamicBuffer2 *b2;
int i;
printf("DynamicBuffer1 length: %d\n",sizeof(struct DynamicBuffer1));
printf("DynamicBuffer2 length: %d\n",sizeof(struct DynamicBuffer2));
b1=(struct DynamicBuffer1*)malloc(sizeof(struct DynamicBuffer1));
b1->len=0;
b1->free=LENGTH;
b1->data=(char *)malloc(sizeof(char)*LENGTH + 1);
b1->data[0] = 100;
b1->free--;
b1->len++;
printf("\nb1->len=%d,b1->free=%d,*(b1->data)=%d\n",b1->len,b1->free,*b1->data);
printf("b1\t\t address: %p\n", b1);
printf("b1->len\t address: %p\n", &(b1->len));
printf("b1->free\t address: %p\n", &(b1->free));
printf("b1->data\t address: %p\n", b1->data);
b2=(struct DynamicBuffer2*)malloc(sizeof(struct DynamicBuffer2)+sizeof(char)*LENGTH + 1);
b2->len=0;
b2->free=LENGTH;
for(i=0;i<LENGTH;i++)
{
b2->data[i]=i;
b2->free--;
b2->len++;
}
printf("\nb2->len=%d,b2->free=%d\n",b2->len,b2->free);
printf("b2\t\taddress: %p\n", b2);
printf("b2->len\taddress: %p\n", &(b2->len));
printf("b2->free\taddress: %p\n", &(b2->free));
printf("b2->data\taddress: %p\n", b2->data);
free(b1->data);
free(b1);
free(b2);
}
用例輸出:
DynamicBuffer1 length: 16
DynamicBuffer2 length: 8
b1->len=1,b1->free=4,*(b1->data)=100
b1 address: 0x1ae7010
b1->len address: 0x1ae7010
b1->free address: 0x1ae7014
b1->data address: 0x1ae7030
b2->len=5,b2->free=0
b2 address: 0x1ae7050
b2->len address: 0x1ae7050
b2->free address: 0x1ae7054
b2->data address: 0x1ae7058
可見(jiàn)捌治,通過(guò)零長(zhǎng)數(shù)組定義的DynamicBuffer2占用的內(nèi)存空間只有8個(gè)字節(jié)(兩個(gè)整形變量的空間),且data數(shù)組地址緊鄰DynamicBuffer2的內(nèi)存地址纽窟。Redis的SDS API也使用了類似的方式肖油,提供了二進(jìn)制安全的動(dòng)態(tài)長(zhǎng)度字符串功能。