《C++ 对象模型》第19页有这样一句话
C程序员的巧计有时候却成为c++程序员的陷阱。例如把单一元素的数组放在一个struct的末尾,于是每个struct objects可以拥有可变数组的数组:
struct mumble
{
/* stuff */
char pc[1];
};
//从文件或标准输入装置中取得一个字符串
//然后为struct 本身和该字符配置足够的内存
struct mumble * pmumbl = (struct mumble*)
malloc(sizeof(struct mumble) + strlen(string) +1);
strcpy(&mumble.pc,string);
正好之前看MCP++的cache acess组件的时候也发现THashMap等结构体在结构体末尾使用了单一元素的数组,说明这一技巧确实用的广泛,现在看看其原理:
结构体的末尾定义了一个char数组,只分配了1个字符。那怎么能说是可变大小数组。
malloc函数分配了一堆的内存。大小为结构体+字符串+1(字符串结束符)
指针pmumbl指向的是malloc所分配的整个内存,而pmumbl->pc指向的是这块内存的第一个字节,因为malloc操作为整个string分配了足够的内存,所以在strcpy的时候,虽然溢出了pc的内存范围,但没有溢出struct的内存范围,使得strcpy的结果就是合理的且可控的。相当于struct拥有了可变大小的数组
C++中 public、protected、private内的声明顺序可以被保证,但是这三个关键字的布局是不同的。因此总的排列顺序并不能被保证。因此,不一定能实现struct的可变大小的数组,建议是不要那么做。
下面看一下代码验证:
using namespace std;
typedef struct mumble
{
/* stuff */
char pc[1];
} mumble;
int main(int argc, char **argv){
mumble raw;
raw.pc[0] = 'a';
cout << "raw " << sizeof(raw) << endl;
char str[10] = "abcdefgxa";
mumble* mumptr = (mumble*)malloc(sizeof(mumble) + strlen(str));
strcpy_s(mumptr->pc,strlen(str) + 1, str);
cout << "mumptr " << sizeof(*mumptr) << endl;
cout << mumptr->pc << endl;
free(mumptr);
}
打印结果:sizeof并不能获取mumptr的真实大小,但是通过下标访问确实能够访问到pc
raw 1
mumptr 1
abcdefgxa
内存分布图:
会发现内存中确实有值:
所以以后定义可变包结构时候,结构中没有可变包的大小,而是只要在结构里最后加一个元素的字节数组就可以。