c/c++中的一些基礎知識

(1)、const 與#define

 const在C++中包含了更豐富的含義,而在C語言中僅意味着:“只能讀的普通變量,”或“不能改變的變量”,故在編譯階段需要的常數仍然只能以#DEFIEN宏定義!故在C語言中如下程序時非法的:

 const int SIZE = 10;

 char a[SIZE];錯誤:SIZE不是常數!


(2)、static變量初始化的問題

 看下面代碼:

#include


int main(void)

{

    int i = 0;

    for(i=0; i<5; i++)

    {

        static int a = 10;

        printf("static a is [%d]\n",a);

        a++;

    }

    return 0;

}


該代碼打印出如下內容:

static a is 10

static a is 11

static a is 12

static a is 13

static a is 14


該代碼說明變量在定義爲static變量後,初始化只進行一次。


(3)、externC問題

    1.被extern “C”限定的函數或變量是extern類型的

    2.被extern “C”修飾的函數或變量是按照C語言編譯和鏈接的


C++和C在編譯時的區別:

C++支持函數重載,而C不支持

例如:函數 viod foo(int x, int y);在C++中編譯後在符號庫中的名字是_foo_int_int,而C編譯後生成的名字是_foo.


一句話概括extern “C”的目的:

實現C++和C及其他語言的混合編程。


具體用法:

1.在C++中引用C語言中的函數和變量,在包含C語言頭文件是,需進行下列處理:

extern "C"

{

    #include "cExample.h"

}


2.在C中引用C++語言中的函數和變量,C++頭文件中需添加extern “C”,而在C語言中不能直接引用聲明瞭extern “C”的頭文件,而應該僅將C文件中在C++中定義的extern “C”函數聲明爲extern類型

例如:

C++頭文件

#ifndef CPP_EXAMPLE_H

#define CPP_EXAMPLE_H

extern "C" int add(int x, int y);

#endif

C++實現文件cpp_Example.cpp

#include "cppExample.h"

int add(int x, int y)

{

    return x + y;

}


C 實現函數Cfile.c

extern int add(int x, int y)

int main(int argc, char* argv[])

{

    add(2, 3);return 0;;

}


(4)、什麼是宏定義

1.宏定義“像”函數;

2.宏定義不是函數,因而需要括上所有參數;

3.宏定義可能產生副作用;

例如:

#define MIN(a,b) ((a) < (b) ? (a) : (b))


(5)、void和void 指針深層探討

規則:在C語言中,凡是不加返回值類型限定的函數,就會被編譯器作爲返回×××值處理,但很多程序員卻誤認爲其爲void類型。

1.任何類型的指針都可以直接賦值給void*類型的指針,無需進行強制類型轉換。但是void*指針卻不可以不進行強制類型轉換而直接就賦值給其他類型的指針。

2.如果函數沒有返回值,應聲明爲void類型。

3.如果函數無參數,那麼應聲明其參數爲void類型。在C語言中可以給無參數的函數傳送任意類型的參數,但是在C++中不能向無參數的函數傳送任何參數,錯誤提示:function does not take 1 parameters.所以無論是C還是C++,若函數不接受任何參數,應將其聲明爲void類型。

4按照ANSI(American National Standards Institute)標準,不能對void指針進行算法操作,這是因爲ANSI標準認定:進行算法操作的指針必須是確定知道其指向類型大小的。例如:

int *ptr;

ptr++;

ptr++的結果是使其增大sizeof(int).

但是GNU則不這麼認定,它指定void*的算法操作和char*一致。

5.如果函數的參數可以是任意類型指針,那麼應將其聲明爲void*類型。

典型的如內存操作函數:

void * memcpy(void *dest, const void *src, size_t len);

void * memset(void *buffer, int c,size_t num);

這樣,任何類型的指針都可以傳入memcpy和memset中,這也真實的體現了內存操作函數的意義,因爲它操作的對象僅僅是一片內存,而無論這片內存是什麼類型!

6.void不能代表一個真實的變量

如void a;錯誤


(6)、內存分配方式

內存分配方式有3中:

1. 從靜態存儲區域分配。內存在程序編譯的時候就已經分配好,這塊內存在程序的整個運行期間都存在,例如全局變量,static變量。

2.在棧上創建,在執行函數時,函數內部的局部變量的存儲單元都是可以在棧上創建的。函數執行結束時這些存儲單元自動被釋放,棧內存分配運算內置於處理器的指令集中,效率很高,但是分配的內存容量有限。

3。在堆上分配,亦稱動態內存分配,程序在運行的時候用malloc或new申請任意多少的內存,程序員自己負責在何時用free或delete釋放內存,動態內存的生存期由我們決定,使用靈活,但是容易出錯。


(7)、內存操作注意事項

1.用malloc或new申請內存之後,應該立即檢查指針值是否爲NULL,防止使用指針值爲NULL的內存。

2.不要忘記爲數組和動態內存賦初值,防止將未被初始化的內存作爲右值使用。

3。避免數組或指針的下標越界,特別要當心發生多1或者少1的操作。

4.動態內存的申請和釋放必須配對,防止內存泄露。

5.用free或delete釋放了內存之後,立即將指針設置爲NULL,防止產生"野指針".

"野指針"不是NULL指針,是指向”垃圾“內存的指針。


(8)、如何判斷大小端格式

編寫一個C函數,若處理器是big_endian的,則返回0,若是little_endian的,則返回1;

int checkCPU(void)

{

    {

     union w

    {

        int a;

        char b;

    }c;

    c.a = 0x1234;

    return(c.b == 0x34);

    }

}


同樣的功能:linux操作系統中的相關源代碼是這麼做的:

static union{char c[4];unsigned long I;}enddian_test = {{'l','?','?','b'}};

#define ENDIANNESS ((char)endian_test.I)

如果ENDIANNESS = l,則爲小端格式,反之;


總結:

在C C++程序的編寫中,當多個基本數據類型或複合數據結構要佔用同一片內存時,我們要使用聯合體;當多種類型,多個對象,多個事物只取其一時,我們也可以使用聯合體來發揮長處!


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