引入
在C中将一个一个元素的数组放在struct的末尾,可以令每个struct的对象拥有可变数组
code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| #include <stdio.h> #include <stdlib.h> #include <string.h> struct Test{ int xixi ; char haha[1]; };
int main() { const char *str = "hhhhhhh"; struct Test *test = (struct Test*)(malloc(sizeof(struct Test) + strlen(str) + 1)); test->xixi = 15; strcpy(test->haha,str); return 0; }
|
gdb 分析
1 2 3 4 5 6 7 8 9 10 11 12 13
| (gdb) p &test $1 = (struct Test **) 0x29ff28 (gdb) p &test->xixi $2 = (int *) 0x9a1180 (gdb) x/32xb test 0x9a1180: 0x0f 0x00 0x00 0x00 0x68 0x68 0x68 0x68 # 从 0f 可以看出是大端序 0x9a1188: 0x68 0x68 0x68 0x00 0x0d 0xf0 0xad 0xba # 连续7个 0x68 对应的是 "hhhhhhh" 0x9a1190: 0xab 0xab 0xab 0xab 0xab 0xab 0xab 0xab 0x9a1198: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 (gdb) p test->haha[0] $4 = 104 'h' (gdb) p test->haha[3] $5 = 104 'h'
|
在代码中也可以使用 printf("%c",test->haha[0])
来访问 ( 我记得应该有边界保护的呀??? )
这个小技巧基本不能在 c++ 中使用,因为 class 中 可以保证相同 access section(public, private,protected) 的数据排列是按照声明顺序排列在内存中,但跨 access section 的数据却不一定是按声明顺序。
1 2 3 4 5 6
| ... private: /** date1 **/ public: /** date2 **/ ...
|
在内存中 date2 并不一定都排列在 date1 后面。再加上 virtual function ,使得这个方法的有效性更加不确定。(不用就行啦 嘻嘻)
遗留问题
一、c++ 到底干了啥??
strcpy(&test->haha,str);
and strcpy(test->haha,str);
在 c99 中都可,但 c++14 只支持后者。同样,c++ 中 strcpy(&(test->haha),str);
也不行
1 2 3 4 5 6 7 8 9
| int main() { const char *str = "hhhhhhh"; struct Test *test = (struct Test*)(malloc(sizeof(struct Test) + strlen(str) + 1)); test->xixi = 15; strcpy(test->haha,str); printf("%x\n",test->haha); fflush(stdout); return 0; }
|
1 2 3 4
| printf("%x\n",test->haha); -> 55121c
(gdb) p &(test->haha) $1 = (char (*)[2]) 0x55121c
|
可以看到这俩都是 haha 的地址,但后者就是编译不过,所以 c++ 在兼容 c 的时候又干了啥呐?
二、反黑技术哪家强。。
之前有看到,为了防止黑客推理出内存中的数据,所以每次 main帧都不是从栈的最低部开始存的,这个很好验证,每次重新运行,(gdb) p &test
可以看到每次地址都不一样就对了。but … 为什么我 p 出来每次都是一样的??(含泪微笑)
猜测一:领会错了该反黑秘籍
猜测二:需要 release 模式,或者编译优化
三、说好的边界保护呐