1. 程式人生 > >C中不安全函式

C中不安全函式

 C 中大多數緩衝區溢位問題可以直接追溯到標準 C 庫。最有害的罪魁禍首是不進行自變數檢查的、有問題的字串操作(strcpy、strcat、sprintf 和 gets)。一般來講,象“避免使用 strcpy()”和“永遠不使用 gets()”這樣嚴格的規則接近於這個要求。

       今天,編寫的程式仍然利用這些呼叫,因為從來沒有人教開發人員避免使用它們。某些人從各處獲得某個提示,但即使是優秀的開發人員也會被這弄糟。他們也許在危險函式的自變數上使用自己總結編寫的檢查,或者錯誤地推論出使用潛在危險的函式在某些特殊情況下是“安全”的。

       第 一位公共敵人是 gets()。永遠不要使用 gets()。該函式從標準輸入讀入使用者輸入的一行文字,它在遇到 EOF 字元或換行字元之前,不會停止讀入文字。也就是:gets() 根本不執行邊界檢查。因此,使用 gets() 總是有可能使任何緩衝區溢位。作為一個替代方法,可以使用方法 fgets()。它可以做與 gets() 所做的同樣的事情,但它接受用來限制讀入字元數目的大小引數,因此,提供了一種防止緩衝區溢位的方法。例如,不要使用以下程式碼:

void main()
  {
  char buf[1024];
  gets(buf);
  }

而使用以下程式碼:

#define BUFSIZE 1024

void main()
  {
  char buf[BUFSIZE];
  fgets(buf, BUFSIZE, stdin);
  }

C 程式設計中的主要陷阱

C 語言中一些標準函式很有可能使您陷入困境。但不是所有函式使用都不好。通常,利用這些函式之一需要任意輸入傳遞給該函式。這個列表包括:

  • strcpy()
  • strcat()
  • sprintf()
  • scanf()
  • sscanf()
  • fscanf()
  • vfscanf()
  • vsprintf
  • vscanf()
  • vsscanf()
  • streadd()
  • strecpy()
  • strtrns()

壞訊息是我們推薦,如果有任何可能,避免使用這些函式。好訊息是,在大多數情況下,都有合理的替代方法。我們將仔細檢查它們中的每一個,所以可以看到什麼構成了它們的誤用,以及如何避免它。

strcpy()函式將源字串複製到緩衝區。沒有指定要複製字元的具體數目。複製字元的數目直接取決於源字串中的數目。如果源字串碰巧來自使用者輸入,且沒有專門限制其大小,則有可能會陷入大的麻煩中!

如果知道目的地緩衝區的大小,則可以新增明確的檢查:

if(strlen(src) >= dst_size) {
  /* Do something appropriate, such as throw an error. */
  }
       else {
  strcpy(dst, src);

完成同樣目的的更容易方式是使用 strncpy() 庫例程:

strncpy(dst, src, dst_size-1);
  dst[dst_size-1] = '\0'; /* Always do this to be safe! */

如果 src 比 dst 大,則該函式不會丟擲一個錯誤;當達到最大尺寸時,它只是停止複製字元。注意上面呼叫 strncpy() 中的 -1。如果 src 比 dst 長,則那給我們留有空間,將一個空字元放在 dst 陣列的末尾。

當然,可能使用 strcpy() 不會帶來任何潛在的安全性問題,正如在以下示例中所見:

strcpy(buf, "Hello!");

即使這個操作造成 buf 的溢位,但它只是對幾個字元這樣而已。由於我們靜態地知道那些字元是什麼,並且很明顯,由於沒有危害,所以這裡無須擔心 ― 當然,除非可以用其它方式覆蓋字串“Hello”所在的靜態儲存器。

確保 strcpy() 不會溢位的另一種方式是,在需要它時就分配空間,確保通過在源字串上呼叫 strlen() 來分配足夠的空間。例如:

dst = (char *)malloc(strlen(src));
  strcpy(dst, src);

strcat()函式非常類似於 strcpy(),除了它可以將一個字串合併到緩衝區末尾。它也有一個類似的、更安全的替代方法 strncat()。如果可能,使用 strncat() 而不要使用 strcat()。

函式 sprintf()和 vsprintf()是用來格式化文字和將其存入緩衝區的通用函式。它們可以用直接的方式模仿 strcpy() 行為。換句話說,使用 sprintf() 和 vsprintf() 與使用 strcpy() 一樣,都很容易對程式造成緩衝區溢位。例如,考慮以下程式碼:

void main(int argc, char **argv)
  {
  char usage[1024];
  sprintf(usage, "USAGE: %s -f flag [arg1]\n", argv[0]);
  }

我們經常會看到類似上面的程式碼。它看起來沒有什 麼危害。它建立一個知道如何呼叫該程式字串。那樣,可以更改二進位制的名稱,該程式的輸出將自動反映這個更改。 雖然如此, 該程式碼有嚴重的問題。檔案系統傾向於將任何檔案的名稱限制於特定數目的字元。那麼,您應該認為如果您的緩衝區足夠大,可以處理可能的最長名稱,您的程式會 安全,對嗎?只要將 1024 改為對我們的作業系統適合的任何數目,就好了嗎?但是,不是這樣的。通過編寫我們自己的小程式來推翻上面所說的,可能容易地推翻這個限制:

void main()
  {
  execl("/path/to/above/program", 
  <<insert really long string here>>, 
  NULL);
  }

函式 execl() 啟動第一個引數中命名的程式。第二個引數作為 argv[0] 傳遞給被呼叫的程式。我們可以使那個字串要多長有多長!

那麼如何解決 {v}sprintf() 帶來得問題呢?遺憾的是,沒有完全可移植的方法。某些體系結構提供了 snprintf() 方法,即允許程式設計師指定將多少字元從每個源複製到緩衝區中。例如,如果我們的系統上有 snprintf,則可以修正一個示例成為:

void main(int argc, char **argv)
  {
  char usage[1024];
  char format_string = "USAGE: %s -f flag [arg1]\n";
  snprintf(usage, format_string, argv[0], 
  1024-strlen(format_string) + 1); 
  }

注意,在第四個變數之前,snprintf() 與 sprintf() 是一樣的。第四個變數指定了從第三個變數中應被複制到緩衝區的字元最大數目。注意,1024 是錯誤的數目!我們必須確保要複製到緩衝區使用的字串總長不超過緩衝區的大小。所以,必須考慮一個空字元,加上所有格式字串中的這些字元,再減去格式 說明符 %s。該數字結果為 1000, 但上面的程式碼是更具有可維護性,因為如果格式字串偶然發生變化,它不會出錯。

{v}sprintf() 的許多(但不是全部)版本帶有使用這兩個函式的更安全的方法。可以指定格式字串本身每個自變數的精度。例如,另一種修正上面有問題的 sprintf() 的方法是:

void main(int argc, char **argv)
  {
  char usage[1024];
  sprintf(usage, "USAGE: %.1000s -f flag [arg1]\n", argv[0]); 
  }

注意,百分號後與 s 前的 .1000。該語法表明,從相關變數(本例中是 argv[0])複製的字元不超過 1000 個。

如果任一解決方案在您的程式必須執行的系統上行不通,則最佳的解決方案是將 snprintf() 的工作版本與您的程式碼放置在一個包中。可以找到以 sh 歸檔格式的、自由使用的版本;請參閱參考資料

繼續, scanf系列的函式也設計得很差。在這種情況下,目的地緩衝區會發生溢位。考慮以下程式碼:

void main(int argc, char **argv)
  {
  char buf[256];
  sscanf(argv[0], "%s", &buf);
  }

如果輸入的字大於 buf 的大小,則有溢位的情況。幸運的是,有一種簡便的方法可以解決這個問題。考慮以下程式碼,它沒有安全性方面的薄弱環節:

void main(int argc, char **argv)
  {
  char buf[256];
  sscanf(argv[0], "%255s", &buf);
  }

百分號和 s 之間的 255 指定了實際儲存在變數 buf 中來自 argv[0] 的字元不會超過 255 個。其餘匹配的字元將不會被複制。

接下來,我們討論 streadd()和 strecpy()。由於,不是每臺機器開始就有這些呼叫,那些有這些函式的程式設計師,在使用它們時,應該小心。這些函式可以將那些含有不可讀字元的字串轉換成可列印的表示。例如,考慮以下程式:

#include <libgen.h>

void main(int argc, char **argv)
  {
  char buf[20];
  streadd(buf, "\t\n", "");
  printf(%s\n", buf);
  }

該程式列印:

\t\n

而不是列印所有空白。如果程式設計師沒有預料到需要 多大的輸出緩衝區來處理輸入緩衝區(不發生緩衝區溢位),則 streadd() 和 strecpy() 函式可能有問題。如果輸入緩衝區包含單一字元 ― 假設是 ASCII 001(control-A)― 則它將列印成四個字元“\001”。這是字串增長的最壞情況。如果沒有分配足夠的空間,以至於輸出緩衝區的大小總是輸入緩衝區大小的四倍,則可能發生緩 衝區溢位。

另一個較少使用的函式是 strtrns(),因為許多機器上沒有該函 數。函式 strtrns() 取三個字串和結果字串應該放在其內的一個緩衝區,作為其自變數。第一個字串必須複製到該緩衝區。一個字元被從第一個字串中複製到緩衝區,除非那個 字元出現在第二個字串中。如果出現的話,那麼會替換掉第三個字串中同一索引中的字元。這聽上去有點令人迷惑。讓我們看一下,將所有小寫字元轉換成大寫 字元的示例:

#include <libgen.h>

void main(int argc, char **argv)
  {
  char lower[] = "abcdefghijklmnopqrstuvwxyz";
  char upper[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
  char *buf;
  if(argc < 2) {
  printf("USAGE: %s arg\n", argv[0]);
  exit(0);
  } buf = (char *)malloc(strlen(argv[1]));
  strtrns(argv[1], lower, upper, buf);
  printf("%s\n", buf);
  }

以上程式碼實際上不包含緩衝區溢位。但如果我們使用了固定大小的靜態緩衝區,而不是用 malloc() 分配足夠空間來複制 argv[1],則可能會引起緩衝區溢位情況。

避免內部緩衝區溢位

realpath() 函式接受可能包含相對路徑的字串,並將它轉換成指同一檔案的字串,但是通過絕對路徑。在做這件事時,它展開了所有符號連結。

該 函式取兩個自變數,第一個作為要規範化的字串,第二個作為將儲存結果的緩衝區。當然,需要確保結果緩衝區足夠大,以處理任何大小的路徑。分配的 MAXPATHLEN 緩衝區應該足夠大。然而,使用 realpath() 有另一個問題。如果傳遞給它的、要規範化的路徑大小大於 MAXPATHLEN,則 realpath() 實現內部的靜態緩衝區會溢位!雖然實際上沒有訪問溢位的緩衝區,但無論如何它會傷害您的。結果是,應該明確不使用 realpath(),除非確保檢查您試圖規範化的路徑長度不超過 MAXPATHLEN。

其它廣泛可用的呼叫也有類 似的問題。經常使用的 syslog() 呼叫也有類似的問題,直到不久前,才注意到這個問題並修正了它。大多數機器上已經糾正了這個問題,但您不應該依賴正確的行為。最好總是假定程式碼正執行在可 能最不友好的環境中,只是萬一在哪天它真的這樣。getopt() 系列呼叫的各種實現,以及 getpass() 函式,都可能產生內部靜態緩衝區溢位問題。如果您不得不使用這些函式,最佳解決方案是設定傳遞給這些函式的輸入長度的閾值。

自己模擬 gets() 的安全性問題以及所有問題是非常容易的。 例如,下面這段程式碼:

char buf[1024];
  int i = 0;
  char ch;
  while((ch = getchar()) != '\n')
  {
  if(ch == -1) break;
  buf[i++] = ch;

哎呀!可以用來讀入字元的任何函式都存在這個問題,包括 getchar()、fgetc()、getc() 和 read()。

緩衝區溢位問題的準則是:總是確保做邊界檢查。

C 和 C++ 不能夠自動地做邊界檢查,這實在不好,但確實有很好的原因,來解釋不這樣做的理由。邊界檢查的代價是效率。一般來講,C 在大多數情況下注重效率。然而,獲得效率的代價是,C 程式設計師必須十分警覺,並且有極強的安全意識,才能防止他們的程式出現問題,而且即使這些,使程式碼不出問題也不容易。

在 現在,變數檢查不會嚴重影響程式的效率。大多數應用程式不會注意到這點差異。所以,應該總是進行邊界檢查。在將資料複製到您自己的緩衝區之前,檢查資料長 度。同樣,檢查以確保不要將過大的資料傳遞給另一個庫,因為您也不能相信其他人的程式碼!(回憶一下前面所討論的內部緩衝區溢位。)

其它危險是什麼?

遺憾的是,即使是系統呼叫的“安全”版本 ― 譬如,相對於 strcpy() 的 strncpy() ― 也不完全安全。也有可能把事情搞糟。即使“安全”的呼叫有時會留下未終止的字串,或者會發生微妙的相差一位錯誤。當然,如果您偶然使用比源緩衝區小的結 果緩衝區,則您可能發現自己處於非常困難的境地。

與 我們目前所討論的相比,往往很難犯這些錯誤,但您應該仍然意識到它們。當使用這類呼叫時,要仔細考慮。如果不仔細留意緩衝區大小,包括 bcopy()、fgets()、memcpy()、snprintf()、strccpy()、strcadd()、strncpy() 和 vsnprintf(),許多函式會行為失常。

另一個要避免的系統呼叫是 getenv()。使用 getenv() 的最大問題是您從來不能假定特殊環境變數是任何特定長度的。我們將在後續的專欄文章中討論環境變數帶來的種種問題。

到 目前為止,我們已經給出了一大堆常見 C 函式,這些函式容易引起緩衝區溢位問題。當然,還有許多函式有相同的問題。特別是,注意第三方 COTS 軟體。不要設想關於其他人軟體行為的任何事情。還要意識到我們沒有仔細檢查每個平臺上的每個常見庫(我們不想做那一工作),並且還可能存在其它有問題的調 用。

即使我們檢查了每個常見庫的各個地方,如果我們試圖聲稱已經列出了將在任何時候遇到的所有問題,則您應該持非常非常懷疑的態度。我們只是想給您起一個頭。其餘全靠您了。

Java 和堆疊保護可以提供幫助

如上一篇專欄文章中所提到的(請參閱 參考資料), 堆疊搗毀是最惡劣的一種緩衝區溢位攻擊,特別是,當在特權模式下搗毀了堆疊。這種問題的優秀解決方案是非可執行堆疊。 通常,利用程式碼是在程式堆疊上編寫,並在那裡執行的。(我們將在下一篇專欄文章中解釋這是如何做到的。)獲取許多作業系統(包括 Linux 和 Solaris)的非可執行堆疊補丁是可能的。(某些作業系統甚至不需要這樣的補丁;它們本身就帶有。)

非可執行堆疊涉及到一些效能問題。(沒有免費的午餐。)此外,在既有堆疊溢位又有堆溢位的程式中,它 們易出問題。可以利用堆疊溢位使程式跳轉至利用程式碼,該程式碼被放置在堆上。 沒有實際執行堆疊中的程式碼,只有堆中的程式碼。這些基本問題非常重要,我們將在下一篇專欄文章中專門刊載。

當然,另一種 選項是使用型別安全的語言,譬如 Java。較溫和的措施是獲取對 C 程式中進行陣列邊界檢查的編譯器。對於 gcc 存在這樣的工具。這種技術可以防止所有緩衝區溢位,堆和堆疊。不利的一面是,對於那些大量使用指標、速度是至關重要的程式,這種技術可能會影響效能。但是 在大多數情況下,該技術執行得非常好。

Stackguard 工具實現了比一般性邊界檢查更為有效的技術。它將一些資料放在已分配資料堆疊的末尾,並且以後會在緩衝區溢位可能發生前,檢視這些資料是否仍然在那裡。這 種模式被稱之為“金絲雀”。(威爾士的礦工將 金絲雀放在礦井內來顯示危險的狀況。當空氣開始變得有毒時,金絲雀會昏倒,使礦工有足夠時間注意到並逃離。)

Stackguard 方法不如一般性邊界檢查安全,但仍然相當有用。Stackguard 的主要缺點是,與一般性邊界檢查相比,它不能防止堆溢位攻擊。一般來講,最好用這樣一個工具來保護整個作業系統,否則,由程式呼叫的不受保護庫(譬如,標 準庫)可以仍然為基於堆疊的利用程式碼攻擊打開了大門。

類似於 Stackguard 的工具是記憶體完整性檢查軟體包,譬如,Rational 的 Purify。這類工具甚至可以保護程式防止堆溢位,但由於效能開銷,這些工具一般不在產品程式碼中使用。

結束語

函式 嚴重性 解決方案
gets 最危險 使用 fgets(buf, size, stdin)。這幾乎總是一個大問題!
strcpy 很危險 改為使用 strncpy。
strcat 很危險 改為使用 strncat。
sprintf 很危險 改為使用 snprintf,或者使用精度說明符。
scanf 很危險 使用精度說明符,或自己進行解析。
sscanf 很危險 使用精度說明符,或自己進行解析。
fscanf 很危險 使用精度說明符,或自己進行解析。
vfscanf 很危險 使用精度說明符,或自己進行解析。
vsprintf 很危險 改為使用 vsnprintf,或者使用精度說明符。
vscanf 很危險 使用精度說明符,或自己進行解析。
vsscanf 很危險 使用精度說明符,或自己進行解析。
streadd 很危險 確保分配的目的地引數大小是源引數大小的四倍。
strecpy 很危險 確保分配的目的地引數大小是源引數大小的四倍。
strtrns 危險 手工檢查來檢視目的地大小是否至少與源字串相等。
realpath 很危險(或稍小,取決於實現) 分配緩衝區大小為 MAXPATHLEN。同樣,手工檢查引數以確保輸入引數不超過 MAXPATHLEN。
syslog 很危險(或稍小,取決於實現) 在將字串輸入傳遞給該函式之前,將所有字串輸入截成合理的大小。
getopt 很危險(或稍小,取決於實現) 在將字串輸入傳遞給該函式之前,將所有字串輸入截成合理的大小。
getopt_long 很危險(或稍小,取決於實現) 在將字串輸入傳遞給該函式之前,將所有字串輸入截成合理的大小。
getpass 很危險(或稍小,取決於實現) 在將字串輸入傳遞給該函式之前,將所有字串輸入截成合理的大小。
getchar 中等危險 如果在迴圈中使用該函式,確保檢查緩衝區邊界。
fgetc 中等危險 如果在迴圈中使用該函式,確保檢查緩衝區邊界。
getc 中等危險 如果在迴圈中使用該函式,確保檢查緩衝區邊界。
read 中等危險 如果在迴圈中使用該函式,確保檢查緩衝區邊界。
bcopy 低危險 確保緩衝區大小與它所說的一樣大。
fgets 低危險 確保緩衝區大小與它所說的一樣大。
memcpy 低危險 確保緩衝區大小與它所說的一樣大。
snprintf 低危險 確保緩衝區大小與它所說的一樣大。
strccpy 低危險 確保緩衝區大小與它所說的一樣大。
strcadd 低危險 確保緩衝區大小與它所說的一樣大。
strncpy 低危險 確保緩衝區大小與它所說的一樣大。
vsnprintf 低危險 確保緩衝區大小與它所說的一樣大。

轉載自:http://blog.csdn.net/uniquecapo/article/details/38235149

相關推薦

C安全函式

 C 中大多數緩衝區溢位問題可以直接追溯到標準 C 庫。最有害的罪魁禍首是不進行自變數檢查的、有問題的字串操作(strcpy、strcat、sprintf 和 gets)。一般來講,象“避免使用 strcpy()”和“永遠不使用 gets()”這樣嚴格的規則接近於這個要求。

c安全函式

 C 中大多數緩衝區溢位問題可以直接追溯到標準 C 庫。最有害的罪魁禍首是不進行自變數檢查的、有問題的字串操作(strcpy、strcat、sprintf 和 gets)。一般來講,象“避免使用 strcpy()”和“永遠不使用 gets()”這樣嚴格的規則接近於這個要求。

在VS2013 使用C語言庫函式,出現出現錯誤,提示使用安全函式use _CRT_SECURE_NO_WARNINGS

在VS 2013 中編譯 C 語言專案,如果使用了 scanf 函式,編譯時便會提示如下錯誤: error C4996: 'scanf': This function or variable may be unsafe. Consider using scanf_s instead. To disab

sort函式的用法(C++排序庫函式的呼叫)對陣列進行排序,在c++有庫函式幫我們實現,這們就需要我們自己來程式設計進行排序了。

對陣列進行排序,在c++中有庫函式幫我們實現,這們就不需要我們自己來程式設計進行排序了。 (一)為什麼要用c++標準庫裡的排序函式 Sort()函式是c++一種排序方法之一,學會了這種方法也打消我學習c++以來使用的氣泡排序和選擇排序所帶來的執行效率不高的問題!因為它使用

C++為什麼建構函式能定義為虛擬函式

關於C++為什麼不支援虛擬建構函式,Bjarne很早以前就在C++Style and Technique FAQ裡面做過回答 Avirtual call is a mechanism to get work done given partialinformation. In particular

C++純虛擬函式的實現原理是什麼,為什麼該純虛擬函式能例項化?

虛擬函式的原理採用 vtable。 類中含有純虛擬函式時,其vtable 不完全,有個空位。 即“純虛擬函式在類的vftable表中對應的表項被賦值為0。也就是指向一個不存在的函式。由於編譯器絕對不允許有呼叫一個不存在的函式的可能,所以該類不能生成物件。在它的派生類中,除非

消除VS對使用安全函式的error

方法一:.在預編譯標頭檔案stdafx.h裡(注意:一定要在沒有include任何標頭檔案之前)定義下面的巨集:   #define _CRT_SECURE_NO_WARNINGS 方法二:更改預處理定義:   專案->屬性->配置屬性->C/C++ -

c++能被申明為虛擬函式函式

常見的不不能宣告為虛擬函式的有:普通函式(非成員函式);靜態成員函式;內聯成員函式;建構函式;友元函式。 1.為什麼C++不支援普通函式為虛擬函式? 普通函式(非成員函式)只能被overload,不能被override,宣告為虛擬函式也沒有什麼意思,因此編譯器會在編譯時邦定

學習C++的有用函式

1: int __builtin_popcount(int x) long long __builtin_popcountll(long long x) 求數字x二進位制中的1的個數 實測: #include<cstdio> int main() { long lon

C++std::getline()函式的用法

https://blog.csdn.net/lzuacm/article/details/52691450 std::getline 在標頭檔案 中定義. getline從輸入流中讀取字元, 並把它們轉換成字串. 1) 的行為就像UnformattedInputFunction, 除

C++string erase 函式的使用 C++string erase函式的使用

轉 C++中string erase函式的使用 2017年04月05日 21:02:17 It_BeeCoder 閱讀數:4286 更多

C++巨集與函式的區別

巨集在編譯時就被替換成它內部的語句了,而函式是執行時呼叫的 所以如果是簡單的東西就寫成巨集,這樣沒有呼叫函式的開銷,效率會高一些。相反,由於巨集每被呼叫一次,就相當於把程式碼複製一份,所以如果比較複雜的巨集被多次呼叫的話,會增加程式碼的體積。因此,太複雜的運算就寫成函式比較好了。 另外,要注意在巨集

c++ 預設定義 函式過載 引用

##概要 本片部落格 的主要內容有, c++中函式預設定義、 函式過載的機制 、函式名在VS環境下編譯後的修改,引用 及其 注意事項。最後列了一個表 文章目錄 預設定義 預設引數 預設引數的分類

關於Cprintf()輸出函式的佔位符(格式制定符)的字元寬設定

很多人應該知道stdio.h標頭檔案裡面的printf()函式 第一個引數是輸出字串 後面的引數是代替字串中所出現的佔位符的值 我相信下面這個用法肯定大部分人都知道 %.3f輸出浮點數的小數部分的三位 printf("%.3f", 0.12345); //輸出0.123 但

《隨筆九》—— C++的 “ 虛擬函式

目錄 定義虛擬函式 三種呼叫虛擬函式的方式比較 虛擬函式的訪問方法 看不懂可以先看這個:《隨筆八》—— C++中的“ 多型中的靜態聯編 、動態聯編”https://blog.csdn.net/qq_34536551/article/details/84195882 虛

C++,getline函式的詳解

C++中本質上有兩種getline函式,一種在標頭檔案<istream>中,是istream類的成員函式。一種在標頭檔案<string>中,是普通函式。 在<istream>中的getline函式有兩種過載形式: istream&am

C++ 執行緒函式為靜態函式 及 類成員函式作為回撥函式

 執行緒函式為靜態函式:   執行緒控制函式和是不是靜態函式沒關係,靜態函式是在構造中分配的地址空間,只有在析構時才釋放也就是全域性的東西,不管執行緒是否執行,靜態函式的地址是不變的,並不在執行緒堆疊中static只是起了一個裝飾的作用,所以二者並沒有必然的關係   執行緒也是一種

C++的虛擬函式和解構函式的定義和作用

虛擬函式 定義: C++中的虛擬函式的作用是允許在派生類中重新定義與基類同名的函式,並且可以通過基類指標或引用來訪問基類和派生類中的同名函式。 虛擬函式的使用方法是: 在基類用virtual宣告成員函式為虛擬函式。這樣就可以在派生類中重新定義此函式,為它賦予新的功能,並能

C++的仿函式,std::function和bind()的用法

1.仿函式:又叫std::function,是C++中的一個模板類 2.C語言中的函式指標: int  add(int a,int b) {   return a+b; } typedef int (*func)(int,int);//給函式型別定義別名

《隨筆十六》——C#的 “ 虛擬函式

目錄 使用基類的引用 虛方法 和覆寫方法 覆寫標記為override 的方法 覆蓋屬性 建構函式初始化語句 使用基類的引用 ●  派生類的例項由基類的例項加上派生類新增的成員組成。  派生類的引用指向整個類物件,包括基類部分。 如果