不正确编译引发内存错误

来源:互联网 发布:器乐培训行业数据 编辑:程序博客网 时间:2024/06/04 20:34
--------------------------------------------------------------------------------
author: hjjdebug
date:   Thu Jul 17 11:20:59 CST 2014
--------------------------------------------------------------------------------
这里演示的编译错误
不是普通的无类型,无函数原型, 格式不正确错误。这些错误可以由编译器指出。
而是编译,连接已经通过,由于编译不完整造成的错误。

运行时出现:
Cannot access memory at address , 内存错误

引起内存错误的原因有多种,这是其中的一种。 而且,往往会令你目瞪口呆,百思不得其解。
这里就来详细揭示其过程。

演示:
一个代码。 file1 文件为A 类, file2 文件为B 类, B 类使用了A 类变量,
A 类头文件更改,而使用它的file2 未编译会是什么结果。
--------------------------------------------------------------------------------
准备简单的测试代码 file1.cpp(file1.h), file2.cpp(file2.h)
--------------------------------------------------------------------------------
[hjj@hjj ~/test]$ cat file1.h file1.cpp
#ifndef _FILE_1
#define _FILE_1
typedef struct _A
{
    int a;
// 第一次不加aa 变量生成执行文件。结果正常。
// 第二次加aa 变量,但只编译file1, 演示不正确的连接会是什么结果
//    int aa;        
    int b;
    int c;
}A;
#endif
#include <stdio.h>
#include "file1.h"
#include "file2.h"
int main(int argc, char *argv[])
{
    A x;
    x.a = 1;
    x.b = 2;
    x.c = 3;
    B y;
    y.printv(&x);
    return 0;
}

[hjj@hjj ~/test]$ cat file2.h file2.cpp
#ifndef _FILE_2
#define _FILE_2
#include "file1.h"
class B
{
    public:
        void set(A *o){m_o=o;}
        void printv(A *x);
    private:
        A* m_o;
};
#endif
#include <stdio.h>
#include "file2.h"
void B::printv(A *x)
{
    printf("a: %d\n",x->a);
    printf("b: %d\n",x->b);
    printf("c: %d\n",x->c);
}
--------------------------------------------------------------------------------
Makefile:
file2.o 也依赖于file1.h, 但这里故意没有写,造成编译不完整
一些不完善的Makefile, 有可能存在这些瑕疵。
--------------------------------------------------------------------------------
[hjj@hjj ~/test]$ cat Makefile
all: test
    
test:    file1.o file2.o
    g++ -o test file1.o file2.o
file1.o : file1.cpp file1.h
    g++ -c -g -o $@ $<
file2.o : file2.cpp file2.h
    g++ -c -g -o $@ $<
clean:
    rm *~ *.o test
[hjj@hjj ~/test]$


--------------------------------------------------------------------------------
gdb 调试: 真相大白。
--------------------------------------------------------------------------------
[hjj@hjj ~/test]$ gdb test
GNU gdb (GDB) 7.6
(gdb) b main
Breakpoint 1 at 0x4005b3: file file1.cpp, line 7.
(gdb) r
Starting program: /home/hjj/test/test

Breakpoint 1, main (argc=1, argv=0x7fffffffe2b8) at file1.cpp:7
7        x.a = 1;
(gdb) n
8        x.b = 2;
(gdb)
9        x.c = 3;
(gdb)
11        y.printv(&x);
(gdb) p x
$1 = {a = 1, aa = 32767, b = 2, c = 3}
(gdb) ptype x
type = struct _A {
    int a;
    int aa;
    int b;
    int c;
}
(gdb) p &x
$2 = (A *) 0x7fffffffe1c0
--------------------------------------------------------------------------------
这之前我们看到的a,b,c 都已正确赋值
--------------------------------------------------------------------------------

(gdb) s
B::printv (this=0x7fffffffe1b0, x=0x7fffffffe1c0) at file2.cpp:5
5        printf("a: %d\n",x->a);
(gdb) p x
$3 = (A *) 0x7fffffffe1c0
(gdb) p *x
$4 = {a = 1, b = 32767, c = 2}
(gdb) ptype x
type = struct _A {
    int a;
    int b;
    int c;
} *
--------------------------------------------------------------------------------
调用函数之后, b 值,c 值忽然不对=了。你是否非常惊讶,
谁改变了b值,c值??
打印它的类型,发现file2 的B 类型与 file1中的B 类型不一致!
编译出的.o 文件, 是按照偏移来访问成员变量的,而不是按照所谓的名称。
这些结构信息保存在.o调试信息中,gdb 可以识别出来。
这里的b值,c值,是结构基地址加偏移。 这里的b,c值是按照旧结构,而调用者按照新结构。
数据运算必然会造成混乱。 尤其是当结构中包含指针。 后面拿不到正确指针,造成非法访问内存。
所以说,没有人改变b值,c值,是对不上口造成的。
--------------------------------------------------------------------------------
(gdb)

解决办法: make clean, make all.
解决所有依赖关系
0 0