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中。如果你在開發程序的時候沒有注意到這個問題,你已經引入了一個嚴重的錯誤。

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