联合体 struct 成员中的数组被赋值超出了界限的问题
- C/C++ code
struct tag_header { u32 size; u32 tag;};/////////////////////////////////////////////////////////////////////////////////struct tag_videotext { u8 x; u8 y; u16 video_page; u8 video_mode; u8 video_cols; u16 video_ega_bx; u8 video_lines; u8 video_isvga; u16 video_points;};/////////////////////////////////////////////////////////////////////////////////struct tag_cmdline { char cmdline[1]; /* this is the minimum size (U-Boot 源代码注释如此)*/ // char cmdline[0]; // 结果如上一样.};/////////////////////////////////////////////////////////////////////////////////struct tag_videolfb { u16 lfb_width; u16 lfb_height; u16 lfb_depth; u16 lfb_linelength; u32 lfb_base; u32 lfb_size; u8 red_size; u8 red_pos; u8 green_size; u8 green_pos; u8 blue_size; u8 blue_pos; u8 rsvd_size; u8 rsvd_pos;};/////////////////////////////////////////////////////////////////////////////////// 其他的结构体定义就省略了, 留个最长的和最短的 struct tag { struct tag_header hdr; union { struct tag_core core; struct tag_mem32 mem; struct tag_videotext videotext; struct tag_ramdisk ramdisk; struct tag_initrd initrd; struct tag_serialnr serialnr; struct tag_revision revision; struct tag_videolfb videolfb; struct tag_cmdline cmdline; /* * Acorn specific */ struct tag_acorn acorn; /* * DC21285 specific */ struct tag_memclk memclk; } u;}; char * src_str = "root=/dev/mtdblock 2 init=/linuxrc console=ttySAC0";strcpy(p->u.cmdline.cmdline, src_str); // p 是一个指向结构体 tag 的指针/** 这段代码是 u-uoot(bootloader) 中的一段. 好像是在 linux 下 arm-linux-gcc 编译的. * 我实验时用的 Code:blocks(GCC) & VC++6 编译运行的.******************************************************************************************* 我的问题是:* 因为结构体 struct cmdline 的大小就 1 字节, 而字符串大小为 50 字节. * 而联合体内最大的一个成员是结构体 videolfb, 其大小为 24 字节. 把 50Byte 字符串* 复制到 cmdline[1] 里, 输出结果是正确的. 把 cmdline[1] 改成指针形式 char * cmdline; * 输出是错误的, 这个可以理解(乱指嘛)! 但是改成 cmdline[0] 输出结果也是正确的. 是不是超出* 的字节按照数组的形式顺序排列存储(标准好像有这个规定??) 超出的字节存储在哪里? * 不会覆盖掉其他内存空间的内容吗? 超出了联合体 u 的界限为啥不报错? 不理解.* 这样写会不会是隐藏的危险? 毕竟是底层的引导代码, 硬件相关性很大. 不怕出错么?* 想了一下午, 还是上来问下 CSDN 的大侠们. 可能我知识有盲点, 希望大家指出, 介绍点资料.* 问的有点多, 谢谢大家了!!!!!!!!!*/[解决办法]
从代码来看,这里主要是强调了首地址,应该是p在某个地方有申请了大于50个字节的空间。
[解决办法]
联合体是以其中最大一个来分配大小
[解决办法]
strcpy不会检查dest的长度
用6.0的话,你可以加断点,看内存内容,就可以看到多余的东西放到哪儿了。p->u的大小应该是tag_videolfb大,所以你strcpy的时候不会错
你试着让src_str很长很长试试...
- C/C++ code
char *src_str = "root=/dev/mtdblock 2 init=/linuxrc console=ttySAC0;root=/dev/mtdblock 2 init=/linuxrc console=ttySAC0;root=/dev/mtdblock 2 init=/linuxrc console=ttySAC0;root=/dev/mtdblock 2 init=/linuxrc console=ttySAC0;root=/dev/mtdblock 2 init=/linuxrc console=ttySAC0;root=/dev/mtdblock 2 init=/linuxrc console=ttySAC0;root=/dev/mtdblock 2 init=/linuxrc console=ttySAC0;root=/dev/mtdblock 2 init=/linuxrc console=ttySAC0;root=/dev/mtdblock 2 init=/linuxrc console=ttySAC0;root=/dev/mtdblock 2 init=/linuxrc console=ttySAC0;root=/dev/mtdblock 2 init=/linuxrc console=ttySAC0;root=/dev/mtdblock 2 init=/linuxrc console=ttySAC0;root=/dev/mtdblock 2 init=/linuxrc console=ttySAC0;root=/dev/mtdblock 2 init=/linuxrc console=ttySAC0;root=/dev/mtdblock 2 init=/linuxrc console=ttySAC0;root=/dev/mtdblock 2 init=/linuxrc console=ttySAC0;root=/dev/mtdblock 2 init=/linuxrc console=ttySAC0;root=/dev/mtdblock 2 init=/linuxrc console=ttySAC0;root=/dev/mtdblock 2 init=/linuxrc console=ttySAC0;root=/dev/mtdblock 2 init=/linuxrc console=ttySAC0;root=/dev/mtdblock 2 init=/linuxrc console=ttySAC0;root=/dev/mtdblock 2 init=/linuxrc console=ttySAC0;root=/dev/mtdblock 2 init=/linuxrc console=ttySAC0;root=/dev/mtdblock 2 init=/linuxrc console=ttySAC0;root=/dev/mtdblock 2 init=/linuxrc console=ttySAC0;root=/dev/mtdblock 2 init=/linuxrc console=ttySAC0;root=/dev/mtdblock 2 init=/linuxrc console=ttySAC0;root=/dev/mtdblock 2 init=/linuxrc console=ttySAC0;root=/dev/mtdblock 2 init=/linuxrc console=ttySAC0;root=/dev/mtdblock 2 init=/linuxrc console=ttySAC0;root=/dev/mtdblock 2 init=/linuxrc console=ttySAC0;root=/dev/mtdblock 2 init=/linuxrc console=ttySAC0;root=/dev/mtdblock 2 init=/linuxrc console=ttySAC0;root=/dev/mtdblock 2 init=/linuxrc console=ttySAC0;root=/dev/mtdblock 2 init=/linuxrc console=ttySAC0;root=/dev/mtdblock 2 init=/linuxrc console=ttySAC0;root=/dev/mtdblock 2 init=/linuxrc console=ttySAC0;root=/dev/mtdblock 2 init=/linuxrc console=ttySAC0;root=/dev/mtdblock 2 init=/linuxrc console=ttySAC0;root=/dev/mtdblock 2 init=/linuxrc console=ttySAC0;root=/dev/mtdblock 2 init=/linuxrc console=ttySAC0;root=/dev/mtdblock 2 init=/linuxrc console=ttySAC0;root=/dev/mtdblock 2 init=/linuxrc console=ttySAC0;root=/dev/mtdblock 2 init=/linuxrc console=ttySAC0;root=/dev/mtdblock 2 init=/linuxrc console=ttySAC0;root=/dev/mtdblock 2 init=/linuxrc console=ttySAC0;root=/dev/mtdblock 2 init=/linuxrc console=ttySAC0;root=/dev/mtdblock 2 init=/linuxrc console=ttySAC0;root=/dev/mtdblock 2 init=/linuxrc console=ttySAC0;root=/dev/mtdblock 2 init=/linuxrc console=ttySAC0;root=/dev/mtdblock 2 init=/linuxrc console=ttySAC0;root=/dev/mtdblock 2 init=/linuxrc console=ttySAC0;root=/dev/mtdblock 2 init=/linuxrc console=ttySAC0;root=/dev/mtdblock 2 init=/linuxrc console=ttySAC0;root=/dev/mtdblock 2 init=/linuxrc console=ttySAC0;root=/dev/mtdblock 2 init=/linuxrc console=ttySAC0;root=/dev/mtdblock 2 init=/linuxrc console=ttySAC0;root=/dev/mtdblock 2 init=/linuxrc console=ttySAC0;root=/dev/mtdblock 2 init=/linuxrc console=ttySAC0;root=/dev/mtdblock 2 init=/linuxrc console=ttySAC0;root=/dev/mtdblock 2 init=/linuxrc console=ttySAC0;root=/dev/mtdblock 2 init=/linuxrc console=ttySAC0;root=/dev/mtdblock 2 init=/linuxrc console=ttySAC0;root=/dev/mtdblock 2 init=/linuxrc console=ttySAC0;root=/dev/mtdblock 2 init=/linuxrc console=ttySAC0;root=/dev/mtdblock 2 init=/linuxrc console=ttySAC0;root=/dev/mtdblock 2 init=/linuxrc console=ttySAC0;root=/dev/mtdblock 2 init=/linuxrc console=ttySAC0;root=/dev/mtdblock 2 init=/linuxrc console=ttySAC0;root=/dev/mtdblock 2 init=/linuxrc console=ttySAC0;root=/dev/mtdblock 2 init=/linuxrc console=ttySAC0;root=/dev/mtdblock 2 init=/linuxrc console=ttySAC0;root=/dev/mtdblock 2 init=/linuxrc console=ttySAC0;root=/dev/mtdblock 2 init=/linuxrc console=ttySAC0;root=/dev/mtdblock 2 init=/linuxrc console=ttySAC0;root=/dev/mtdblock 2 init=/linuxrc console=ttySAC0;root=/dev/mtdblock 2 init=/linuxrc console=ttySAC0;root=/dev/mtdblock 2 init=/linuxrc console=ttySAC0;root=/dev/mtdblock 2 init=/linuxrc console=ttySAC0;root=/dev/mtdblock 2 init=/linuxrc console=ttySAC0;root=/dev/mtdblock 2 init=/linuxrc console=ttySAC0;root=/dev/mtdblock 2 init=/linuxrc console=ttySAC0;root=/dev/mtdblock 2 init=/linuxrc console=ttySAC0;root=/dev/mtdblock 2 init=/linuxrc console=ttySAC0;root=/dev/mtdblock 2 init=/linuxrc console=ttySAC0;root=/dev/mtdblock 2 init=/linuxrc console=ttySAC0;root=/dev/mtdblock 2 init=/linuxrc console=ttySAC0;root=/dev/mtdblock 2 init=/linuxrc console=ttySAC0;root=/dev/mtdblock 2 init=/linuxrc console=ttySAC0;root=/dev/mtdblock 2 init=/linuxrc console=ttySAC0;root=/dev/mtdblock 2 init=/linuxrc console=ttySAC0;root=/dev/mtdblock 2 init=/linuxrc console=ttySAC0;root=/dev/mtdblock 2 init=/linuxrc console=ttySAC0;root=/dev/mtdblock 2 init=/linuxrc console=ttySAC0;root=/dev/mtdblock 2 init=/linuxrc console=ttySAC0;root=/dev/mtdblock 2 init=/linuxrc console=ttySAC0;root=/dev/mtdblock 2 init=/linuxrc console=ttySAC0;root=/dev/mtdblock 2 init=/linuxrc console=ttySAC0;root=/dev/mtdblock 2 init=/linuxrc console=ttySAC0;root=/dev/mtdblock 2 init=/linuxrc console=ttySAC0;root=/dev/mtdblock 2 init=/linuxrc console=ttySAC0;";
[解决办法]
Q:是不是超出的字节按照数组的形式顺序排列存储?
A:当然,C只会管向哪里写数据与写多少数据,不会管边界问题。
Q:超出的字节存储在哪里?
A:顺序存储。
Q:不会覆盖掉其他内存空间的内容吗?
A:当然会覆盖
Q:超出了联合体 u 的界限为啥不报错?
A:报错了就不叫纯C了,只能这样才能保证C的小巧精悍
Q:这样写会不会是隐藏的危险?
A:明显不能这样写,一出现野指针程序就乱了。
Q:介绍点资料.
A:几乎大部分C语言书都有挺详细的介绍,不过这类问题可以自己用最简单的printf("%x%x",...)方式就很深刻理解了。
[解决办法]
简单地说,C语言只检查你写的代码中有没有语法错误,不管你编写的程序运行起来会不会造成系统崩溃
[解决办法]
strcpy 是不安全的函数 ,建议使用 strncpy,如果要提高效率建议用 memccpy。
[解决办法]
strncpy(des,src,n);des[n]=0;