對malloc的返回值應該如何轉型

本文歸納敘述了一篇老文的內容,而且總結對malloc返回值的3種轉型方式,(相對於原文)更全面的總結其各自的應用範圍。

1. 原文內容
2. 對malloc的3種轉型方式
3. 各自的應用範圍html

 

 

之前有篇文章叫《C/C++ 誤區 —— 強制轉換 malloc() 的返回值》。
文章大體內容是:

1. malloc函數在<stdlib.h> 或者 <cstdlib>頭文件中,而不是<malloc.h>。web


2. 因爲C語言最初沒有void類型,因此是使用char*來表明通用指針。函數

/*  the old declaration of malloc  */
char *  malloc(size_t size);

char *  p  =  malloc(size  *   sizeof ( * p) );
/*  能夠, 不須要轉型  */

T1
*  p1  =  malloc(size1  *   sizeof ( * p1) );
/*  (T1!=char不能夠,char*不能隱式轉換成T1*   */

T2
*  p2  =  (T2 * )malloc(size2  *   sizeof ( * p2) );
/*  (T2!=char) 能夠,顯示類型轉換  */

 

3.C語言後來引入了void類型,就可使用void*表明通用指針,同時規定void*能夠隱式轉換任意指針類型。
spa

/*  the new declaration of malloc  */
void *  malloc(size_t size);

char *  p  =  malloc(size  *   sizeof ( * p) );
/*  仍然能夠,void*能夠隱式轉換到任意指針類型  */

T1
*  p1  =  malloc(size1  *   sizeof ( * p1) );
/*  如今能夠,void*能夠隱式轉換到任意指針類型  */

T2
*  p2  =  (T1 * )malloc(size2  *   sizeof ( * p2) );
/*  仍然能夠,但再也不必須  */


4. 在引入了void以後的C語言中,再使用強制轉換是多此一舉,同時影響代碼維護。
而且說這是一個C/C++的誤區指針

 


原文概述完畢,開始說本文章的內容:
對malloc返回值的轉型,大體有如下三種方式:

 

1. 僅在C中orm

/* legal only in C */
htm

/* 新頭文件 */
T
* p = malloc(size * sizeof(*p) ); /* T!=void */blog


/* 舊頭文件 */繼承

T* p = ( T*)malloc(size* sizeof(*p) ); /*  T!= void */


2.僅在C++中
C++自然支持void,可是不容許void*隱式轉換到任意類型指針,須要static_cast。ci

// legal only in C++

// 新頭文件
T* p = static_cast<T*>( malloc(size * sizeof(*p) ));

// 舊頭文件(目前還有這種編譯器嗎?)
T* p = reinterpret_cast<T*>( malloc(size * sizeof(*p) ));

// 固然在C++中應該考慮
T* p = new T[size];
// 或者
std::vector<T> p(size);
// 但這不是文章討論重點


3.在C/C++中

/*  legal in both C and C++  */
/*  legal in both new  and old header  */
T
*  p  =  (T * )malloc(size  *   sizeof ( * p) );

 


第1種對新頭文件的轉型方式,如同代碼第1行所說,在C編譯器中合法。
由於C++不支持void*到其餘指針類型的隱式轉換。
因此,原文章說這是C/C++的誤區,並不許確。
這僅僅是(引入void類型以後的)C語言中的「非必須」的動做,是不是誤區,還有待考量。

第2種對新舊頭文件的轉型方式,代碼第1行也說了,在C++編譯器中合法。

由於C編譯器不認識static_cast或者reinterpret_cast。


第3種,是一種中庸的寫法。
如同代碼第1行所說:此代碼不管是在C仍是C++編譯器,不管是新頭文件仍是舊頭文件,都是合法的代碼。是可移植性最好的代碼。

由於代碼中使用的(C風格的)轉型、malloc——C/C++都支持。

因此,這種寫法並不必定是誤區或者多此一舉
由於代碼的做者也許比原文章的做者對移植性(C和C++的新舊編譯器)考慮更多。

一個排版比較好的原文轉載連接
http://programmingart.blog.51cto.com/213782/43503

 

 

學長,問您個很基礎的問題,C風格的強制類型轉換會觸發對應的構造函數麼?static_cast和reinterpret_cast會麼?另外這兩個轉換符具體作了些什麼?

強制轉換都不會觸發構造函數。

 
static_cast用於隱式轉換過程,如:
short  s;  int  i;
=  s;  // 能夠,向更寬整數類型進行隱式轉換。
=  i;  // 警告,向更窄整數類型轉換。
=  static_cast < short > (i);  // 過程,明確代表代碼做者的意圖,警告消除。
 
base *  b; derived *  d;
=  d;  //  能夠,向上轉型,隱式轉換。
=  b;  //  錯誤,向下轉型,不容許。
=  static_cast < derived *> (b);  //  能夠,向上轉型的過程。但不保證正確
 
object *  o;  void *  p;
=  o;  //  能夠,任何指針類型均可以隱式轉換到void*
=  p;  //  過程是錯誤,除非
=  static_cast < object *> (o);  //  能夠,但不保證正確
 
 
reinterpret_cast用於整數和指針之間,無繼承關係的指針之間的轉換。
按照其二進制表示,從新解釋( Re- Interpret),如:
T *  p; intptr_t i;
=  reinterpret_cast < intptr_t > (p);
//  將p的地址,解釋成一個整數。
=  reinterpret_cast < T *> (i);
//  將i的值,解釋成一個指向T的指針。
 
T1 *  p1; T2 *  p2;
p1 
=  reinterpret_cast < T1 *> (p2);
//  將p2中保存的地址的值,複製到p1。
//  由於p1是T1*類型的指針,之後對p1的操做,將按T1*來解釋

//  另一種方式:
p1  =  static_cast < T1 *> static_cast < void *> (p2) );

 

若是一個用戶自定義類型C, 有一個能夠經過單個類型爲T的參數進行調用的構造函數, 那麼,該構造函數就定義了一個T到C的轉換。 若是該構造函數是explicit的,T到C的轉換是顯式轉換。 若是該構造函數不是explicit,T到C的轉換是隱式轉換。 例如: class string { char* content_; explicit string(const char* source,int length=-1) :content_(0) { if (length==-1) length = static_cast<int>(strlen(source)); content_ = new char[length+1]; strcpy(source,content_); } }; 這個構造函數能夠經過單個參數調用(第2個參數有默認值),因此這個構造函數定義了一個 const char* 到 string 的轉換。 若是有explicit,那麼該轉換必須是顯式轉換: string s = static_cast<string>("hello"); 若是沒有explict,該轉換能夠是隱式轉換: string s = "hello"; 上面說錯了,這種轉換確實會調用構造函數。

相關文章
相關標籤/搜索