如何定义变长的TLV结构体?
TLV是一种常用的用于通信的结构体格式。T表示tag,L表示length,V表示value。其中T和L是固定大小的,V是可变大小,L表示的是V的长度。通常用于结构化网络通信中的数据流。如0x3 3 'aa\0',0x3 5 'aaaa\0',其中0x3表示tag的值,3 or 5表示的是后面的字符串的长度。由于V是可变长度的,所以在定义TLV结构时,需要将V定义成为可变大小。可定义如下:
struct TLV
{
uint8_t tag;
uint16_t len;
char value[0];
}__attribute__((packed));
注意value分配的是0大小,最后一个成员为可变长的数组,对于TLV(Type-Length-Value)形式的结构,或者其他需要变长度的结构体,用这种方式定义最好。使用起来非常方便,创建时,malloc一段结构体大小加上可变长数据长度的空间给它,可变长部分可按数组的方式访问,释放时,直接把整个结构体free掉就可以了。__attribute__(packed)用来强制不对struct TLV进行4字节对齐,目的是为了获取真实的TLV的空间使用情况。
int main()
{
char *szMsg = "aaaaaaaaa";
cout << sizeof(TLV) << endl; //the size of TLV
uint16_t len = strlen(szMsg) + 1;
struct TLV *pTLV;
pTLV = (struct TLV*)malloc(sizeof(struct TLV) + sizeof(char)*len);
pTLV->tag = 0x2;
pTLV->len = len;
memcpy(pTLV->value, szMsg, len);
cout << pTLV->value << endl;
free(pTLV);
pTLV = NULL;
return 0;
}
这里有关于设置变长TLV的详细说明:
http://www.douban.com/note/213324857/
这里有一个问题,如何实现嵌套TLV结构呢?大家有什么好的思路吗?欢迎交流
简单实现了一下嵌套TLV,不知道有没有问题。
#include <iostream>
using namespace std;
struct TLVNODE
{
uint8_t tag;
uint16_t len;
char value[0];
}__attribute__ ((packed));
struct TLV
{
int hei;
uint8_t tag;
uint16_t len;
struct TLVNODE value[0];
} __attribute__ ((packed));
int main()
{
//char *szMsg = "aaaaaaaaaaa";
cout << sizeof(TLV) << endl;
//uint16_t len = strlen(szMsg) + 1;
char *szNodeMsg = "bbbbbbbbbb";
uint16_t nodelen = strlen(szNodeMsg) + 1;
struct TLVNODE *pNode = (struct TLVNODE *) malloc(sizeof(struct TLVNODE) + sizeof(char)*nodelen);
pNode->tag = 0x3;
pNode->len = nodelen;
memcpy(pNode->value, szNodeMsg, nodelen);
struct TLV *pTlv;
uint16_t nodeSize = sizeof(struct TLVNODE) + sizeof(char)*nodelen;
pTlv = (struct TLV*)malloc(sizeof(struct TLV) + nodeSize);
pTlv->tag = 0x2;
pTlv->len = nodeSize;
// pTlv->value[0] = (struct TLVNODE)*pNode;
memcpy(pTlv->value, pNode, nodeSize);
free(pNode);
pNode = NULL;
cout << sizeof(*pTlv) << endl;
/*for (int i = 0; i < len; ++i)
{
pTlv->value[i] = szMsg[i];
}*/
/*memcpy(pTlv->value, szMsg, len);*/
//cout << pTlv->value << endl;
free(pTlv);
pTlv = NULL;
return 0;
}