读书人

联合体 struct 成员中的数组被赋值超出

发布时间: 2012-09-17 12:06:51 作者: rapoo

联合体 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;

读书人网 >C语言

热点推荐