1. 程式人生 > >ZeroMemory C++ 中 ZeroMemory、memset 危險需慎用

ZeroMemory C++ 中 ZeroMemory、memset 危險需慎用

C++ 中 ZeroMemory、memset 危險需慎用

2016年11月28日 14:11:16 閱讀數:491

使用C/C++程式設計時,常使用ZeroMemory、memset或 “={0}”來對結構體物件進行初始化或清零。然而這三種方式都有各自的特點,使用時需謹慎,否則容易出現嚴重錯誤,本人今日解決一個導致宕機的bug,查了幾小時,才發現是由同事亂用ZeroMemory所致。於是蒐集資料,撰此文以共勉。

memset


void *memset(void *s,int ch,size_t n); 是由C Run-time Library提供的提供的函式,作用是在一段記憶體塊中填充某個給定的值,它是對較大的結構體或陣列進行清零操作的一種最快方法。由於是語言層面提供,所以可跨平臺使用。參考:

http://www.cplusplus.com/reference/cstring/memset/
示例:

[cpp]   view plain  copy
  1. char str[] = "almost every programmer should know memset!";  
  2. memset (str,'-'
    ,6);  
  3. puts (str);  

輸出: [cpp]   view plain  copy
  1. ------ every programmer should know memset!  

ZeroMemory


ZeroMemory是美國微軟公司的軟體開發包SDK中的一個巨集。 其作用是用0來填充一塊記憶體區域。定義式如下

[cpp]   view plain  copy
  1. #define RtlZeroMemory(Destination,Length) memset((Destination),0,(Length))  
  2. #define ZeroMemory RtlZeroMemory  

由此可見:

  1. ZeroMemory實際是用memset實現的。
  2.  ZeroMemory只能用於windows平臺。

注意:

ZeroMemory和memset且於清零時,會將結構中所有位元組置0,如果結構體中有虛擬函式或結構體成員中有虛擬函式,則會將虛擬函式指標置0,如果後續程式呼叫虛擬函式,空指標很可能導致程式崩潰!

因此,有虛擬函式或成員中有虛擬函式的結構體初始化,一定要用建構函式來完成。

另外,如果一個類的結構中包含STL模板(Vector、List、Map等等),那麼使用ZeroMemory對這個類的物件中進行清零操作也會引起一系列的崩潰問題(指標指向記憶體錯誤、迭代器越界訪問等)。所以,再次強烈建議:類(class)只使用建構函式進行初始化,不要呼叫ZeroMemory進行清零操作。

示例:

[cpp]   view plain  copy
  1. #include "stdafx.h"  
  2. #include <Windows.h>  
  3.   
  4. class Car  
  5. {  
  6. public:  
  7.     virtual void Run(){}  
  8. private:  
  9.     int m_speed;  
  10. };  
  11. struct  SRace    
  12. {  
  13.     Car car;  
  14.     int dirver;  
  15. };  
  16.   
  17. int _tmain(int argc, _TCHAR* argv[])  
  18. {  
  19.     SRace race;  
  20.     ZeroMemory(&race,sizeof(race));  
  21.       
  22.     // 沒通過虛表指標呼叫,沒事  
  23.     race.car.Run();  
  24.       
  25.     Car *pCar = &race.car;  
  26.   
  27.     // __vfptr = 0x00000000,崩潰  
  28.     pCar->Run();  
  29.   
  30.     return 0;  
  31. }  

={0}


={0}操作是結構體和陣列的一種初始化方式,它是將結構體中基本型別變數賦預設值,當結構體中有非基本型別(例如類物件)時,會編譯錯誤,這也是一種保護。