C/C++补漏

栈空间的分配方式对普通的程序开发来讲是没有意义的,有系统来完成相关操作,但有时栈空间的分配方式又会显得很重要。栈的分配方式有两种,其一是从高地址空间向低地址空间分配,其二是从低地址空间向高地址空间分配。那么如何确定栈空间的分配方式呢,下述代码可以用来确定栈的分配方式。

复制代码
int fun(){
    static int * pnt = 0;
    if(pnt == 0){
        int abc;
        pnt = &abc;
        fun();
    }
    else{
        int bcd;
        if(pnt > &bcd){
            printf("从高地址向低地址分配");    // Windows的分配方式
        }
        else{
            printf("从低地址向高地址分配");
        }
    }
    return 0;
}
复制代码

+

成员指针的用法。指针可以算作C/C++的短刀利器了,指向类成员的指针包括指向类数据成员的指针和指向类方法(函数)的指针,下述代码演示了这两种指针的用法

复制代码
class AClass{
public:
    AClass():m_name(0), m_age(0) { };
    AClass(const char * name);
    ~AClass();

public:
    void SayHello();
    void SayOkay();

private:
    char * m_name;
    int m_age;

public:
    typedef char * AClass::*PACName;    // 引入新的类型(指向数据成员的指针)
    operator PACName() { return &AClass::m_name; }    // 执行类型转换

    typedef int AClass::*PACAge;
    operator PACAge() { return &AClass::m_age; }

    typedef void (AClass::*Say)();    // 指向成员函数的指针

};

int fun(void){
    AClass a("AClass");
    AClass::Say func = &AClass::SayHello();
    (a.*func)();    // 调用成员函数

    AClass * p = &a;
    func  = &AClass::SayOkay;
    (p->*.func)();    // 调用成员函数

    printf("%s\t%d\n", a.*AClass::PACName(a), a.*AClass::PACAge(a));    
    // 数据成员指针的使用。PS:是不是有些啰嗦?!

}
复制代码

+

对象在内存中的布局。了解对象在内存中的布局,可以很方便的通过数据成员找到包含该数据成员的对象的地址,续而执行更多的操作,这是C/C++的一个奇技淫巧。下面是示例代码

复制代码
struct A{
    int a;
    double b;
    char c;
}

int fun(void){
    A x;
    printf("%x,%x,%x,%x,%d\n", &x, &(x.a), &(x.b), &(x.c), sizeof(x));
    // 运行结果:0x27AC48,0X27AC48,0X27AC50,0x27AC58,24(结构的大小是24而不是13!请参考相关文档)
    // 如果知道了x.a的地址,那么x的地址也就知道了。
    return 0;
}
复制代码

+

new和delete操作符重载。new和delete操作符会经常用到,但对这两个操作符进行重载的却很少,通过这两个操作符的重载,很容易实现把文件当内存来用。还可以通过这两个操作符的重载,来跟踪内存的使用情况,诸如,是否有内存泄露等。

复制代码
//完成内存使用的跟踪(通过重载全局new/delete操作符)
void * operator new (size_t size, char * file, int line){
    // 此处可以填写记录日志代码
    return malloc(size);
}

void * operator delete(void * p){
    // 此处可以填写记录日志代码
    free(p);
}

#define NEW ::new
#define DELETE ::delete
// 接下来就需要使用NEW/DELETE替换掉new/delete了。
复制代码

将对象分配到指定的内存空间(主要用作对象的成员函数来使用)

复制代码
//重载全局new/delete操作符
void * operator(size_t size, void * p){
    return p;
}

void * delete(void * p){
    return;
}

// 成员函数操作符

class ClassA{
public:
    ClassA();

public:
    void * operator new (size_t, void *);
    void operator delete(void* p)

};

void * ClassA::operator new(size_t size, void * p){
    return p;
}

void ClassA::operator delete(void * p){
    return;
}

int fun(void){
    void * p = malloc(sizeof(ClassA));    // 是不是有点画蛇添足的意味?就看你怎么用了
    ClassA a = new(p);
    delete a;
    free(p);
}
复制代码

+

strncpy函数,应该被经常用到,为什么这里要提起呢,因为这个函数隐藏了一个很大的危险,这个危险隐藏的很深,它会导致程序莫名其妙的问题。strncpy函数的原形是strncpy(char* DST, char* SRC, size_t LEN);其解释是,strncpy将从SRC中复制不超过LEN个长度的字符到SRC中(包括NULL字符)。如果SRC的长度小于LEN, NULL字符被添加DES中,并且直到复制了LEN个字符。这里没有强调的是,如果SRC的长度超过了LEN,则NULL字符将不被添加到DST中。如果你在开发程序的时候没有注意到这个问题,你已经引入了一个严重的错误。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章