2013-06-04 120 views
25

我碰到一段代碼就如下:什麼是「if(*((void **)&(_ ptr))!=(void *)NULL)」check?

/* Allocate memory for _ptr */ 

if(*((void **) &(_ptr)) != (void *) NULL) 
{ 
    /* free _ptr */ 
} 

這是什麼從以下不同?

/* Allocate memory for _ptr */ 

if (_ptr != NULL) 
{ 
    /* free _ptr */ 
} 

編輯:_ptr可以是任何類型,實際上,這是一個宏如下:

#define RETURN_MEM_CHK(_ptr) \ 
    {if(*((void **) &(_ptr)) != (void *) NULL){/* free _ptr */} 

對不起帶來混亂。

+3

你是不是指'if(_ptr!= NULL)'? – szx

+15

看起來像一個混淆的C編程競賽中的一行 – djf

+9

這也是不必要的;在指針上調用'free'之前,不需要檢查NULL。 –

回答

16

對於它的價值:

我無法弄清楚這一點我自己,所以我跟我的編譯器討論這一點,他說,條件是相當於*到if (_ptr != NULL)

%gcc -Wall -O2 -g -c convoluted.c; objdump的-d -M英特爾-S convoluted.o

convoluted.o:  file format elf32-i386 
Disassembly of section .text.startup: 

00000000 <main>: 
#include <stdlib.h> 

int main(void) 
{ 
    0: 55      push ebp 
    1: 89 e5     mov ebp,esp 
    3: 83 e4 f0    and esp,0xfffffff0 
    6: 83 ec 10    sub esp,0x10 
    void* _ptr=malloc(1024); 
    9: c7 04 24 00 04 00 00 mov DWORD PTR [esp],0x400 
    10: e8 fc ff ff ff   call 11 <main+0x11> 

    if(*((void **) &(_ptr)) != (void *) NULL) 
    15: 85 c0     test eax,eax 
    17: 74 08     je  21 <main+0x21> 
    { 
     free(_ptr); 
    19: 89 04 24    mov DWORD PTR [esp],eax 
    1c: e8 fc ff ff ff   call 1d <main+0x1d> 
    } 

    return 0; 
} 
    21: 31 c0     xor eax,eax 
    23: c9      leave 
    24: c3      ret  

%的gcc -Wall -O2 -g -c kindanormal.c; objdump的-d -M英特爾-S kindanormal.o

kindanormal.o:  file format elf32-i386 
Disassembly of section .text.startup: 

00000000 <main>: 
#include <stdlib.h> 

int main(void) 
{ 
    0: 55      push ebp 
    1: 89 e5     mov ebp,esp 
    3: 83 e4 f0    and esp,0xfffffff0 
    6: 83 ec 10    sub esp,0x10 
    void* _ptr=malloc(1024); 
    9: c7 04 24 00 04 00 00 mov DWORD PTR [esp],0x400 
    10: e8 fc ff ff ff   call 11 <main+0x11> 

    if(_ptr != NULL) 
    15: 85 c0     test eax,eax 
    17: 74 08     je  21 <main+0x21> 
    { 
     free(_ptr); 
    19: 89 04 24    mov DWORD PTR [esp],eax 
    1c: e8 fc ff ff ff   call 1d <main+0x1d> 
    } 

    return 0; 
} 
    21: 31 c0     xor eax,eax 
    23: c9      leave 
    24: c3      ret  

注意 檢查本身是不是真的有必要要麼,其他人指出。更自然的方法是:

free(_ptr); _ptr = NULL;

*在這個機器上,在此係統中,這GCC版本和CPU,只有當星星在剛剛正確的方式對齊......

+0

我假設你的_ptr是一個指針變量,而不是,例如,一個int? –

+0

該OP表示這是記憶ptr。我沒有探索任何其他場景 – djf

+2

從C語言的角度來看,這個條件當然不是等價的。它恰好在您的特定平臺上相當。 – AnT

3

*((void **) &(_ptr)) != (void *) NULL

這種檢查也適用,其中_ptr不是一個指針類型,例如如果_ptruintptr_t什麼的。在這種情況下,簡單比較_ptr != NULL可能無法處理空指針值沒有「全零」表示的系統。

當然,讀取一個整數作爲指針是不可移植的,所以這段代碼爲一組不同的問題交換了一組問題。

+0

無論系統內部表示是什麼,空指針總是比較等於整數值0。另請參閱此C FAQ條目:http://c-faq.com/null/ptrtest.html – datenwolf

+3

@datenwolf:值爲零的整數常量總是轉換爲空指針值,該值始終與空指針進行比較。空指針值可能不具有全零表示。如果'_ptr'是一個整數類型,但包含空指針的表示(例如通過'memcpy'或類似'*(void *)&_ ptr =(void *)NULL'的類型),那麼它可能會有一個非空-zero _integer_值,並將比較爲不等於零。 –

+0

編輯後的措辭對這句話更清楚。 –

6

那麼,有什麼區別取決於_ptr的類型是什麼。

if (_ptr != NULL) 
如果 _ptr不是指針類型(以及 NULL是一個空指針常數,包括投地 void*

是行不通的,它可以工作,如果NULL僅僅是一個整數,常數值0,即使_ptr不有指針類型)。

如果_ptr具有指針類型,則if (_ptr != NULL)_ptr與空指針進行比較。 Simples。

if(*((void **) &(_ptr)) != (void *) NULL) 

,如果它不調用未定義的行爲,解釋起始地址&_ptr作爲void*sizeof (void*)字節,重新解釋的結果進行比較,以void*類型的空指針。

如果_ptr是與void*不同的表示形式的指針類型的值,那麼它的行爲可能會有所不同。

它適用於_ptr不是指針類型。

在所有合理的情況下,但是,它也只是說

if ((void*)_ptr != NULL) 
12

一個例子那裏可以得到不同的結果更復雜的方式(也沒有,我特別的系統,就當我剛剛試了一下):

int _ptr = 0; 
int whatever = 17; 

if (*((void **) &(_ptr)) != (void *) NULL) { 
    printf("Not equal (1)\n"); 
} 

if (_ptr != NULL) { 
    printf("Not equal (2)\n"); 
} 

第一個版本假裝可變_ptr整數是一個空指針,並且訪問其存儲器,就好像它是一個空指針。在我的計算機上,整數是32位,指針是64位,這意味着讀取變量外部的內存。這當然是未定義的行爲,在這種情況下,它導致條件評估爲真。

你會得到類似的結果,如果_ptr無效*其他的類型的指針,在系統上,其中該指針類型是不同的大小或大於一個空指針來表示不同。

1

*((void **) &(_ptr) 

表達執行由對象_ptr佔用的存儲器區域的原始存儲器重新解釋。第一個sizeof(void *)字節被重新解釋爲void *類型的對象。同時,對象_ptr本身可以有絕對的任何類型。假設它是與void *(或更大尺寸)相同尺寸的物體是自然的。

例如,_ptr可以是某些整數類型適當大小的的對象。顯然,在這種情況下,if (_ptr == NULL)可能只是拒絕以這種NULL定義爲(void *) 0的實現進行編譯。

1

除非_ptr具有void*類型則代碼打破嚴格別名規則和有未定義的行爲:

一個目的應具有其存儲的值僅由具有以下類型中的一個的左值 表達式獲得:76 )

- 一個類型兼容 與有效類型的對象,

- 一型 ℃的合格版本ompatible與有效類型的對象,

- 一個類型是 簽名或對應於有效類型 對象的無符號類型,-a類型是有符號或對應於 合格版本無符號類型有效類型的對象,的

- anaggregate或 ,其包括其 成員(包括,遞歸地,一個子聚集或 含有聯合的amember)中上述類型的一個或

聯合類型 - AC字符類型。

在代碼_ptr通過void*類型,這是隻有兼容與自身的左值訪問,因此沒有以上條件都爲真,否則。

它很有可能像_ptr != NULL一樣工作,但使用這樣的代碼仍然是一種可怕的做法。

相關問題