常见的内存错误【三】

来源:互联网 发布:asp.net系统源码下载 编辑:程序博客网 时间:2024/05/17 01:53

7.  结构的成员顺序变化引发的错误

    在初始化一个结构时,老手可能很少像新手那样老老实实的,一个成员一个成员的为结构初始化,而是采用快捷方式,如:

    Struct s
    {
        int   l;
        char* p;
    };

    int main(int argc, char* argv[])
    {
        struct s s1 = {4, "abcd"};
        return 0;
    }

    以上这种方式是非常危险的,原因在于你对结构的内存布局作了假设。如果这个结构是第三方提供的,他很可能调整结构中成员的相对位置。而这样的调整往往不会在 文档中说明,你自然很少去关注。如果调整的两个成员具有相同数据类型,编译时不会有任何警告,而程序的逻辑上可能相距十万八千里了。
    正确的初始化方法应该是(当然,一个成员一个成员的初始化也行):

    struct s
    {
        int   l;
        char* p;
    };
    int main(int argc, char* argv[])
    {
        struct s s1 = {.l=4, .p = "abcd"};
        struct s s2 = {l:4, p:"abcd"};
        return 0;
    }

8.  结构的大小变化引发的错误

    我们看看下面这个例子:

    struct base
    {
        int n;
    };
    struct s
    {
        struct base b;
        int m;
    };
 
    在OOP中,我们可以认为第二个结构继承了第一结构,这有什么问题吗?当然没有,这是C语言中实现继承的基本手法。
    现在假设第一个结构是第三方提供的,第二个结构是你自己的。第三方提供的库是以DLL方式分发的,DLL最大好处在于可以独立替换。但随着软件的进化,问题可能就来了。
    当第三方在第一个结构中增加了一个新的成员int k;,编译好后把DLL给你,你直接给了客户了。程序加载时不会有任何问题,在运行逻辑可能完全改变!原因是两个结构的内存布局重叠了。解决这类错误的唯一办法就是全部重新相关的代码。
    解决这类错误的唯一办法就是重新编译全部代码。由此看来,DLL并不见得可以动态替换,如果你想了解更多相关内容,建议阅读《COM本质论》。