25

我遇到了一段代码如下:

/* 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 */}

很抱歉带来混乱。

4

6 回答 6

16

物有所值:

我自己无法解决这个问题,所以我和我的编译器讨论了这个问题,他说条件等同于* if (_ptr != NULL)

% gcc -Wall -O2 -g -c convoluted.c; objdump -d -M intel -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 intel -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    

注意 正如其他人指出的那样,检查本身也不是必需的。一种更自然的方法是:

免费(_ptr);_ptr=NULL;

*在这台机器上,使用这个操作系统、这个 GCC 版本和这个 CPU,并且只有当星星以正确的方式对齐时......

于 2013-06-04T09:48:54.153 回答
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是一个 void 指针,并访问它的内存,就好像它是一个 void 指针。在我的计算机上,int 是 32 位,指针是 64 位,这意味着读取变量之外的内存。这当然是未定义的行为,在这种情况下,它导致条件评估为真。

如果_ptr是除void*以外的类型的指针,在该指针类型的大小不同或表示方式与 void 指针不同的系统上,您将获得类似的结果。

于 2013-06-04T10:17:58.010 回答
6

那么,区别是什么取决于类型_ptr是什么。

if (_ptr != NULL )

如果_ptr不是指针类型(并且NULL是一个包含强制转换的空指针常量void*,它可以工作,如果NULL它只是一个值为 0 的整数常量,即使_ptr没有指针类型)。

如果_ptr具有指针类型,则与空指针if (_ptr != NULL )进行比较。_ptr简单的。

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

如果它没有调用未定义的行为,则将sizeof (void*)从 address 开始的字节解释&_ptr为 avoid*并将该重新解释的结果与 type 的空指针进行比较void*

如果_ptr是一个指针类型的值,其表示形式不同于void*.

如果_ptr不是指针类型,它可以工作。

然而,在所有合理的情况下,这只是一种更复杂的说法

if ((void*)_ptr != NULL)
于 2013-06-04T10:13:47.980 回答
3

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

这个检查也适用于_ptr不是指针类型的地方,例如 if _ptrwas auintptr_t或 something。在这种情况下,简单比较_ptr != NULL可能无法处理空指针值没有“全零”表示的系统。

当然,将整数读取为指针也不是可移植的,因此该代码将一组问题换成一组不同的问题。

于 2013-06-04T10:10:55.053 回答
1

*((void **) &(_ptr)

表达式对 object 占用的内存区域执行原始内存重新解释_ptr。第一个sizeof(void *)字节被重新解释为void *类型的对象。同时,对象_ptr本身绝对可以有任何类型。很自然地假设它旨在成为与void *(或更大)大小相同的对象。

例如,_ptr可以是某种适当大小的整数类型的对象。显然,在这种情况下,可能会简单地拒绝在定义为if (_ptr == NULL)的实现中编译。NULL(void *) 0

于 2013-06-06T19:06:08.307 回答
1

除非_ptrvoid*类型,否则代码会违反严格的别名规则并具有未定义的行为:

对象的存储值只能由具有以下类型之一的左值表达式访问:76)

— 与对象的有效类型兼容的类型,

— 与对象的有效类型兼容的类型的限定版本,

— 对应于对象有效类型的有符号或无符号类型, — 对应于对象有效类型的限定版本的有符号或无符号类型,

— 在其成员中包含上述类型之一的聚合或联合类型(递归地包括子聚合或包含联合的成员),或

——一种字符类型。

代码_ptr中是通过类型的左值访问的void*,它只与自身兼容,所以以上条件都不成立。

它很有可能像这样工作,_ptr != NULL但使用这样的代码仍然是一种糟糕的做法。

于 2013-06-07T13:09:27.540 回答