1. 程式人生 > >C++知識點(4)

C++知識點(4)

GCC常用引數

-ansi:關閉 gnu c 中與 ansi c 不相容的特性 , 啟用 ansi c 的專有特性 ( 包括禁止一些 asm inline typeof 關鍵字 , 以及 UNIX,vax 等預處理巨集

-lxx:表示動態載入libxx.so庫

-Lxx:表示增加目錄xx,讓編譯器可以在xx下尋找庫檔案

-Ixx:表示增加目錄xx,讓編譯器可以在xx下尋找標頭檔案

-shared:生成共享目標檔案。通常用在建立共享庫時

-Wall:生成所有警告資訊。一下是具體的選項,可以單獨使用

簡單的GCC語法:

第一是 “-o”,它後面的引數表示要輸出的目標檔案,再一個是 “-c”,表示僅編譯(Compile),不連線(Make),如果沒有”-c”引數,那麼就表示連線,如下面的幾個命令:

gcc –c test.c,表示只編譯test.c檔案,成功時輸出目標檔案test.o

gcc –c test.c –o test.o ,與上一條命令完全相同

gcc –o test test.o,將test.o連線成可執行的二進位制檔案test

gcc –o test test.c,將test.c編譯並連線成可執行的二進位制檔案test

gcc test.c –o test,與上一條命令相同

gcc –c test1.c,只編譯test1.c,成功時輸出目標檔案test1.o

gcc –c test2.c,只編譯test2.c,成功時輸出目標檔案test2.o

gcc –o test test1.o test2.o,將test1.o和test2.o連線為可執行的二進位制檔案test

gcc –c test test1.c test2.c,將test1.o和test2.o編譯並連線為可執行的二進位制檔案test

注:如果你想編譯cpp檔案,那麼請用g++,否則會有類似如下莫名其妙的錯誤:

cc3r3i2U.o(.eh_frame+0x12): undefined reference to `__gxx_personality_v0’……

還有一個引數是”-l”引數,與之緊緊相連的是表示連線時所要的連結庫,比如多執行緒,如果你使用了pthread_create函式,那麼你就應該在編譯語句的最後加上”-lpthread”,”-l”表示連線,”pthread”表示要連線的庫,注意他們在這裡要連在一起寫,還有比如你使用了游標庫curses,那麼呢就應該在後面加上”-lcurses”,比如下面的寫法:

gcc –o test test1.o test2.o –lpthread –lcurses

例如: 在ubuntu 環境下編譯基於course庫函式的程式時,如果不帶 -lncurses時,會出現

screen1.c:(.text+0x12):對‘initscr’未定義的引用
screen1.c:(.text+0x24):對‘wmove’未定義的引用
screen1.c:(.text+0x39):對‘printw’未定義的引用
screen1.c:(.text+0x4a):對‘wrefresh’未定義的引用
screen1.c:(.text+0x5f):對‘endwin’未定義的引用
需使用 gcc -o screen1 screen1.c -lncurses

-x language filename

設定檔案所使用的語言,使字尾名無效,對以後的多個有效.
例子用法:
  gcc -x c hello.pig

-x none filename

關掉上一個選項,也就是讓gcc根據檔名字尾,自動識別檔案型別
例子用法:
  gcc -x c hello.pig -x none hello2.c

-c

只啟用預處理,編譯,和彙編,也就是他只把程式做成obj檔案
例子用法:
  gcc -c hello.c
它將生成.o的obj檔案

-S

只啟用預處理和編譯,就是指把檔案編譯成為彙編程式碼。
例子用法
  gcc -S hello.c
它將生成.s的彙編程式碼,你可以用文字編輯器察看

-E

只啟用預處理,這個不生成檔案,你需要把它重定向到一個輸出檔案裡面.
例子用法:
  gcc -E hello.c > pianoapan.txt
  gcc -E hello.c | more

段錯誤與coredump檔案

Linux下C程式常常會因為記憶體訪問錯誤等原因造成segment fault(段錯誤),此時如果系統core dump功能是開啟的,那麼將會有記憶體映像轉儲到硬碟上來,之後可以用gdb對core檔案進行分析,還原系統發生段錯誤時刻的堆疊情況。這對於我們發現程式bug很有幫助。

core檔案僅僅是一個記憶體映像(同時加上除錯資訊),主要是用來除錯的。遇到某些無法處理的訊號時會產生core檔案。

使用ulimit -a可以檢視系統core檔案的大小限制;使用ulimit -c [kbytes]可以設定系統允許生成的core檔案大小,例如:

ulimit -c 0 //不產生core檔案
ulimit -c 100 //設定core檔案最大為100k
ulimit -c unlimited //不限制core檔案大小

g++ -g -o test test.c
./test
//發生段錯誤
gdb ./test core
(gdb) where
(gdb) r

分析記憶體洩漏

Valgrind通常用來成分析程式效能及程式中的記憶體洩露錯誤,使用到的是其中的memcheck,它用來檢查程式中的記憶體問題,如洩漏、越界、非法指標等。
Valgrind包含下列工具:

1、memcheck:檢查程式中的記憶體問題,如洩漏、越界、非法指標等。
2、callgrind:檢測程式程式碼的執行時間和呼叫過程,以及分析程式效能。
3、cachegrind:分析CPU的cache命中率、丟失率,用於進行程式碼優化。
4、helgrind:用於檢查多執行緒程式的競態條件。
5、massif:堆疊分析器,指示程式中使用了多少堆記憶體等資訊。
6、lackey:
7、nulgrind:

這幾個工具的使用是通過命令:valgrand –tool=name 程式名來分別呼叫的,當不指定tool引數時預設是 –tool=memcheck。

Memcheck

最常用的工具,用來檢測程式中出現的記憶體問題,所有對記憶體的讀寫都會被檢測到,一切對malloc、free、new、delete的呼叫都會被捕獲。所以,它能檢測以下問題:
1、對未初始化記憶體的使用;
2、讀/寫釋放後的記憶體塊;
3、讀/寫超出malloc分配的記憶體塊;
4、讀/寫不適當的棧中記憶體塊;
5、記憶體洩漏,指向一塊記憶體的指標永遠丟失;
6、不正確的malloc/free或new/delete匹配;
7、memcpy()相關函式中的dst和src指標重疊。

這些問題往往是C/C++程式設計師最頭疼的問題,Memcheck能在這裡幫上大忙。

將程式編譯生成可執行檔案後執行:valgrind –leak-check=full ./程式名

動態連結過程

靜態連結的缺點

(1)同一個模組被多個模組連結時,那麼這個模組在磁碟和記憶體中都有多個副本,導致很大一部分空間被浪費了。
(2)當程式的任意一個模組發生更新時,整個程式都要重新連結、釋出給使用者。

動態連結的基本思想

動態就是不對那些組成程式的目標檔案進行連結,等到程式要執行時才進行連結。也就是說,把連結這個過程推遲到了執行時再進行,這就是動態連結(Dynamic Linking)的基本思想。

連結檔案

在Linux 中,ELF的動態連結檔案被稱為動態共享物件(DSO,dynamic shared object),以.so為副檔名的檔案。
在WINDOWS中,EP的動態連結檔案被稱為動態連結庫(DLL,dynamic link library),以 .dll 為副檔名的檔案。

動態連結程式執行時地址空間的分佈

在動態連結程式執行時,除了可執行檔案本身,還有動態連結檔案與動態連結器將被對映到程序的地址空間中,動態連結器被當做普通的共享物件來進行對映,在系統執行可執行檔案之前,會將控制權交給動態連結器,由它完成所有的動態連結工作以後再把控制權交給可執行檔案。

如何確定連結地址

編譯:編譯器對原始檔進行編譯,就是把原始檔中的文字形式存在的原始碼翻譯成機器語言形式的目標檔案的過程,在這個過程中,編譯器會進行一系列的語法檢查。如果編譯通過,就會把對應的CPP轉換成OBJ檔案。
編譯單元:根據C++標準,每一個CPP檔案就是一個編譯單元。每個編譯單元之間是相互獨立並且互相不可知。
目標檔案:由編譯所生成的檔案,以機器碼的形式包含了編譯單元裡所有的程式碼和資料,還有一些其他資訊,如未解決符號表匯出符號表地址重定向表等。目標檔案是以二進位制的形式存在的。

根據C++標準,一個編譯單元(Translation Unit)是指一個.cpp檔案以及這所include的所有.h檔案,.h檔案裡面的程式碼將會被擴充套件到包含它的.cpp檔案裡,然後編譯器編譯該.cpp檔案為一個.obj檔案,後者擁有PE(Portable Executable,即Windows可執行檔案)檔案格式,並且本身包含的就是二進位制程式碼,但是不一定能執行,因為並不能保證其中一定有main函式。當編譯器將一個工程裡的所有.cpp檔案以分離的方式編譯完畢後,再由連結器連結成為一個.exe或.dll檔案。

下面讓我們來分析一下編譯器的工作過程:
我們跳過語法分析,直接來到目標檔案的生成,假設我們有一個A.cpp檔案,如下定義:

    int n = 1;
    void FunA()
    {
        ++n;
    }

它編譯出來的目標檔案A.obj就會有一個區域(或者說是段),包含以上的資料和函式,其中就有n、FunA,以檔案偏移量形式給出可能就是下面這種情況:

偏移量    內容    長度
0x0000    n       4
0x0004    FunA    ??

注意:這只是說明,與實際目標檔案的佈局可能不一樣,??表示長度未知,目標檔案的各個資料可能不是連續的,也不一定是從0x0000開始。
FunA函式的內容可能如下:

    0x0004 inc DWORD PTR[0x0000]
    0x00?? ret

這時++n已經被翻譯成inc DWORD PTR[0x0000],也就是說把本單元0x0000位置的一個DWORD(4位元組)加1。

有另外一個B.cpp檔案,定義如下:

    extern int n;
    void FunB()
    {
        ++n;
    }

它對應的B.obj的二進位制應該是:

偏移量    內容    長度
0x0000    FunB    ??

這裡為什麼沒有n的空間呢,因為n被宣告為extern,這個extern關鍵字就是告訴編譯器n已經在別的編譯單元裡定義了,在這個單元裡就不要定義了。由於編譯單元之間是互不相關的,所以編譯器就不知道n究竟在哪裡,所以在函式FunB就沒有辦法生成n的地址,那麼函式FunB中就是這樣的:

    0x0000 inc DWORD PTR[????]
    0x00?? ret

那怎麼辦呢?這個工作就只能由連結器來完成了。

未解決符號表、匯出符號表、地址重定義表

為了能讓連結器知道哪些地方的地址沒有填好(也就是還????),那麼目標檔案中就要有一個表來告訴連結器,這個表就是“未解決符號表”,也就是unresolved symbol table。同樣,提供n的目標檔案也要提供一個“匯出符號表”也就是exprot symbol table,來告訴連結器自己可以提供哪些地址。

一個目標檔案不僅要提供資料和二進位制程式碼外,還至少要提供兩個表:未解決符號表和匯出符號表,來告訴連結器自己需要什麼和自己能提供些什麼。那麼這兩個表是怎麼建立對應關係的呢?這裡就有一個新的概念:符號。在C/C++中,每一個變數及函式都會有自己的符號,如變數n的符號就是n,函式的符號會更加複雜,假設FunA的符號就是_FunA(根據編譯器不同而不同)。所以,
A.obj的匯出符號表為

符號    地址
n       0x0000
_FunA   0x0004

未解決符號為空(因為他沒有引用別的編譯單元裡的東西)。
B.obj的匯出符號表為

符號    地址
_FunB   0x0000

未解決符號表為

符號    地址
n       0x0001

這個表告訴連結器,在本編譯單元0x0001位置有一個地址,該地址不明,但符號是n。

在連結的時候,連結在B.obj中發現了未解決符號,就會在所有的編譯單元中的匯出符號表去查詢與這個未解決符號相匹配的符號名,如果找到,就把這個符號的地址填到B.obj的未解決符號的地址處。如果沒有找到,就會報連結錯誤。在此例中,在A.obj中會找到符號n,就會把n的地址填到B.obj的0x0001處。

但是,這裡還會有一個問題,如果是這樣的話,B.obj的函式FunB的內容就會變成inc DWORD PTR[0x000](因為n在A.obj中的地址是0x0000),由於每個編譯單元的地址都是從0x0000開始,那麼最終多個目標檔案連結時就會導致地址重複。所以連結器在連結時就會對每個目標檔案的地址進行調整。在這個例子中,假如B.obj的0x0000被定位到可執行檔案的0x00001000上,而A.obj的0x0000被定位到可執行檔案的0x00002000上,那麼實現上對連結器來說,A.obj的匯出符號地地址都會加上0x00002000,B.obj所有的符號地址也會加上0x00001000。這樣就可以保證地址不會重複。

既然n的地址會加上0x00002000,那麼FunA中的inc DWORD PTR[0x0000]就是錯誤的,所以目標檔案還要提供一個表,叫地址重定向表,address redirect table。

總結一下:
目標檔案至少要提供三個表:未解決符號表,匯出符號表和地址重定向表。
未解決符號表:列出了本單元裡有引用但是不在本單元定義的符號及其出現的地址。
匯出符號表:提供了本編譯單元具有定義,並且可以提供給其他編譯單元使用的符號及其在本單元中的地址。
地址重定向表:提供了本編譯單元所有對自身地址的引用記錄。

連結器的工作順序:
當連結器進行連結的時候,首先決定各個目標檔案在最終可執行檔案裡的位置。然後訪問所有目標檔案的地址重定義表,對其中記錄的地址進行重定向(加上一個偏移量,即該編譯單元在可執行檔案上的起始地址)。然後遍歷所有目標檔案的未解決符號表,並且在所有的匯出符號表裡查詢匹配的符號,並在未解決符號表中所記錄的位置上填寫實現地址。最後把所有的目標檔案的內容寫在各自的位置上,再作一些另的工作,就生成一個可執行檔案。
說明:實現連結的時候會更加複雜,一般實現的目標檔案都會把資料,程式碼分成好向個區,重定向按區進行,但原理都是一樣的。
明白了編譯器與連結器的工作原理後,對於一些連結錯誤就容易解決了。

下面再看一看C/C++中提供的一些特性:
extern:這就是告訴編譯器,這個變數或函式在別的編譯單元裡定義了,也就是要把這個符號放到未解決符號表裡面去(外部連結)。

static:如果該關鍵字位於全域性函式或者變數的宣告前面,表明該編譯單元不匯出這個函式或變數,因些這個符號不能在別的編譯單元中使用(內部連結)。如果是static區域性變數,則該變數的儲存方式和全域性變數一樣,但是仍然不匯出符號。

預設連結屬性:對於函式和變數,預設連結是外部連結,對於const變數,預設內部連結。

外部連結的利弊:外部連結的符號在整個程式範圍內都是可以使用的,這就要求其他編譯單元不能匯出相同的符號(不然就會報duplicated external symbols)。
內部連結的利弊:內部連結的符號不能在別的編譯單元中使用。但不同的編譯單元可以擁有同樣的名稱的符號。

為什麼標頭檔案裡一般只可以有宣告不能有定義:標頭檔案可以被多個編譯單元包含,如果標頭檔案裡面有定義的話,那麼每個包含這標頭檔案的編譯單元都會對同一個符號進行定義,如果該符號為外部連結,則會導致duplicated external symbols連結錯誤。

為什麼公共使用的行內函數要定義於標頭檔案裡:因為編譯時編譯單元之間互不知道,如果內聯被定義於.cpp檔案中,編譯其他使用該函式的編譯單元的時候沒有辦法找到函式的定義,因些無法對函式進行展開。所以如果行內函數定義於.cpp裡,那麼就只有這個.cpp檔案能使用它。

陣列和指標

陣列名具有普通變數的直接性,它的地址就是實際陣列首元素的地址。因此它不用取兩次地址裡的內容而是取一次,同時又具有和指標相同的偏移量引用方式,即下標的實現實際是由指標加偏移量實現的。

下標操作中的表現

C語言對指標與陣列的引用方式做了可以“交叉”使用的語法規定。就上面的例子來說,如果p指標指向陣列b時,b[i]、(b+i)、p[i]、(p+i)都是對陣列第i個元素的正確引用方式,這也給很多C語言學習者製造了“指標和陣列一樣”的錯覺。

在函式形參中的表現

在向函式傳遞引數時,如果實參是一個一維陣列,那用於接受的形參為對應的指標。也就是傳遞過去是陣列的首地址而不是整個陣列。這麼做的原因主要是效率,這是無可爭議的,但為了使用上的簡便與通用,C語言接受兩種形參的寫法,即下面3種寫法是相同的

int foo(int *a, int n);  
int foo(int a[], int n); 
int foo(int a[20], int n);  

迭代器失效問題

list,set,map容器

題目: 刪除map

void deleteValueFromMap(Map &m, int n = 5)
{
     MapIt it;
     for(it = m.begin(); it != m.end(); /*不能再自增了*/)
     {
         if(0 == it->second % n)
         {
             m.erase(it++);
         }
         else
         {
             it++;
         }
     }
 }

對於關聯的容器map來說, m.erase(it)後,it就失效了,所以要用m.erase(it++)。這樣一來,it++先執行, 指向了下一個元素,同時返回的還是當前元素, 此時再刪除它就沒有問題了。

或者:

std::list< int> List;
std::list< int>::iterator itList;
for( itList = List.begin(); itList != List.end(); )
{
      if( WillDelete( *itList) )
      {
            itList = List.erase( itList);
       }
       else
            itList++;
}

這裡通過erase方法的返回值也可以獲取下一個元素的位置。

vector,deque容器

而vector中則要這樣處理:

void deleteValueFromVector(Vec &v, int n = 5)
{
     VecIt it;
     for(it = v.begin(); it != v.end(); /*不能再自增了*/)
     {
         if(0 == *it % n)
         {
             it = v.erase(it); // erase的返回值就是指向被刪除的元素的下一個元素的迭代器
         }
         else
         {
             it++;
         }
     }
}

讀寫鎖的實現

使用互斥鎖和條件變數實現讀寫鎖:

class readwrite_lock
{
public:
    readwrite_lock(): stat(0){}

    void readLock()
    {
        mtx.lock();
        while (stat < 0)
            cond.wait(mtx);
        ++stat;
        mtx.unlock();
    }

    void readUnlock()
    {
        mtx.lock();
        if (--stat == 0)
            cond.notify_one(); // 叫醒一個等待的寫操作
        mtx.unlock();
    }

    void writeLock()
    {
        mtx.lock();
        while (stat != 0)
            cond.wait(mtx);
        stat = -1;
        mtx.unlock();
    }

    void writeUnlock()
    {
        mtx.lock();
        stat = 0;
        cond.notify_all(); // 叫醒所有等待的讀和寫操作
        mtx.unlock();
    }

private:
    mutex mtx;
    condition_variable cond;
    int stat; // == 0 無鎖;> 0 已加讀鎖個數;< 0 已加寫鎖
};

使用2個互斥鎖實現讀寫鎖:

class readwrite_lock
{
public:
    readwrite_lock():read_cnt(0){}

    void readLock()
    {
        read_mtx.lock();
        if (++read_cnt == 1)
            write_mtx.lock();

        read_mtx.unlock();
    }

    void readUnlock()
    {
        read_mtx.lock();
        if (--read_cnt == 0)
            write_mtx.unlock();

        read_mtx.unlock();
    }

    void writeLock()
    {
        write_mtx.lock();
    }

    void writeUnlock()
    {
        write_mtx.unlock();
    }

private:
    mutex read_mtx;
    mutex write_mtx;
    int read_cnt; // 已加讀鎖個數
};

相關推薦

C++知識點4

GCC常用引數 -ansi:關閉 gnu c 中與 ansi c 不相容的特性 , 啟用 ansi c 的專有特性 ( 包括禁止一些 asm inline typeof 關鍵字 , 以及 UNIX,vax 等預處理巨集 -lxx:表示動態載入libxx.so

C# 繼承4

報錯 提示 clas PE ron bsp http 調用父類 spa 接上章: class NameList { public NameList() => Console.WriteLine("這個是NameList的構造函數");

淺談C++類4--隱式類型別轉換

分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow 也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!        

初學C語言4

1.在 程式碼中 所有的計算 計算機都是將整數轉換為2進位制後 才進行計算的 2.計算數字二進位制中1的個數:可以計算負數 演算法:while(n!=0) { n=n&(n-1); m++; } 3.斐波那契 : 1 1 2 3 5 8 13 21 F1=1 f2=1 f3=1 F3

c基礎4

1.break。 break 會結束所有的迴圈,同時,break必須出現在迴圈體內。 2.continue。 continue會結束本次迴圈。 3.陣列。 知識點1:如果定義一個數組,一個初值都沒有賦。

boost C++知識點

5 非同步輸入輸出Asio 5.1 概述 本章介紹了 Boost C++ 庫 Asio,它是非同步輸入輸出的核心。 名字本身就說明了一切:Asio 意即非同步輸入/輸出。 該庫可以讓 C++ 非同步地處理資料,且平臺獨立。 非同步資料處理就是指,任務觸發後不需要

C++知識點繼承與派生導學

1.單繼承多繼承   派生類繼承的內容:     原有基類成員,新增新的資料成員函式成員,     一般情況下,建構函式和解構函式不被繼承,而C++11中使用using可以繼承 2.派生類訪問許可權: 公有繼承:     基類的public、protected、private屬性在派生類

C++知識點模板與群體資料

類模板->容器,函式模板->演算法 1.函式模板: 使用情況:演算法邏輯一致,資料型別不一致,需要寫多個過載函式,帶來資料冗餘和更改時的便利 template <typename T>   編譯器會置換T,但需要注意運算子是否過載 2.類模板: temp

C++知識點泛型程式設計與C++STL標準模板庫

1.泛型程式設計 把程式碼從特定的資料結構中分離出來,使得它不依賴於特定的資料結構而更加通用 容器->迭代器->演算法 介面卡 2.概念:用於界定具備一定功能的資料型別 comparable:可比較 Assignable:可賦值 Sortable:可比較且可賦值 3.模型:符合一個

LinuxC/C++程式設計4—管道通訊

管道是Linux為程序提供的一種通訊方式,這裡所說的管道只能用於有血緣關係的程序(一般是子程序和父程序之間)。一般用來做程序同步和程序間通訊。 Linux中提供的有名管道的建立函式為:int pipe(int pipe[2]); pipe(建立管道): 1) 標頭檔案

設計模式 c++版4——模板方法模式

定義: 定義一個操作中的演算法的框架,而將一些步驟延遲到子類中。使得子類可以不改變一個演算法的結構即可重定義該演算法的某些特定步驟。 示例一:模板方法模式(通用版) 1. 類圖10-3 2. 類圖說明: AbstractClass 叫抽象模板,他的方法分為兩類: 基

c#知識點

當使用String str="abc",這種方式時,先去記憶體的Heap中找是否存在"abc"這個字串,若存在,則將地址引用。若不存在則建立。 2.當使用String str=new String("abc");時,不管事先是否存在"abc",每次都會建立其新的物件。S

C#中的方法傳參與switch、if結構4

判斷 1.2 菱形 條件表達式 執行 代碼 輸出 分類 簡易 一、方法傳參的2種方式    1、按值傳遞       傳遞的是值的副本,值會更改但未保留,值最終並未更改     2、按引用傳遞(形參用ref關鍵字修飾)【P86頁】 傳遞的是地址,值會更改且保留,值最終更改

挖一挖C#中那些我們不經常使用的東西之系列4——GetHashCode,ExpandoObject

add 工具 通過 border 後期綁定 main image 代碼 不同 一:GetHashCode   從MSDN上能夠看到的解釋是:用作特定類型的哈希函數,也就是說不論什麽對象的實例都會有一個int32類型的HashCode。而且存放在FCL中的

4C語言——求最大連續子序列和

log spa clas 最大連續子序列和 alloc 最大 code max 連續 題目: 輸入一組整數,求出這組數字子序列和中最大值。也就是只要求出最大子序列的和,不必求出最大的那個序列。例如: 序列:-2 11 -4 13 -5 -2,則最大子序列和為20。 序列:-

C#系列之基礎知識點

命名規則 系列 字符 註釋 編輯器 小數類型 智能 規則 解釋 知識點一:VS啟動方法 第一種:雙擊圖標 第二種:window+R——調出cmd,輸入devenu properties 屬性的意思 知識點二:後綴名解釋 .sln 解決方案文件:包含整個解決方案的信息 .

在VS2012中采用C++中調用DLL中的函數4

color style 屬性 cls weight 項目 新建工程 ifdef xxx 轉自:http://www.cnblogs.com/woshitianma/p/3683495.html 這兩天因為需要用到VS2012來生成一個DLL代碼,但是之前並沒有用過DLL相關

C程序設計導引4

很多 實現 返回 第5章 沒有 i++ bool pac void 第5章 函數 5.1 函數的概念和結構   先來比較兩個概念:過程(procedure)、函數(function)。   過程與函數都是一組封裝在一起的語句,能實現特定的功能。區別在於過程只進行某種操作,而

linux信號解釋4--C語言下的理解

linux信號 C語言下linux信號理解 上一節中中簡單介紹了信號的處理機制,就是調用函數庫來實現信號的處理,因此,在這節中,介紹在C語言下如何理解信號的處理機制。 創建一個文件signal.c,文件內容如下:(對於學過一下C語言的童鞋來說是不是很熟悉呢) #include<signal.h&

C#復習筆記4--C#3:革新寫代碼的方式用智能的編譯器來防錯

靜態 png 字段 tom 父類 保持 int http AI 用智能的編譯器來防錯 本章的主要內容: 自動實現的屬性:編寫由字段直接支持的簡單屬性, 不再顯得臃腫不堪; 隱式類型的局部變量:根據初始值推斷類型,簡化局部變量的聲明; 對象和集合初始化程序:用一個表達式就能