Подтвердить что ты не робот

Что означает "if (* ((void **) & (_ ptr))!= (Void *) NULL)" проверить?

Я натолкнулся на часть кода следующим образом:

/* Allocate memory for _ptr */

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

Чем он отличается от следующего?

/* Allocate memory for _ptr */

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

EDIT: _ptr может быть любым типом, на самом деле это макрос следующим образом:

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

Извините, что вы путаете.

4b9b3361

Ответ 1

Для чего это стоит:

Я не мог понять это самостоятельно, поэтому я обсуждал это с моим компилятором, и он говорит, что условие эквивалентно * на 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 и только тогда, когда звезды выравниваются правильно...

Ответ 2

Один пример, где он мог бы дать разные результаты (и сделал, в моей конкретной системе, когда я только что попробовал):

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 является указателем на пустоту и обращается к ее памяти, как если бы она была указателем на пустоту. На моем компьютере, где ints - 32 бита, а указатели - 64 бита, это означает чтение памяти вне переменной. Это, конечно, поведение undefined, и в этом случае это привело к условию, равному true.

Вы получите похожие результаты, если _ptr - это указатель типа, отличного от void *, в системе, где этот тип указателя имеет разный размер или представлен иным образом указатель void.

Ответ 3

Ну, какая разница зависит от типа _ptr.

if (_ptr != NULL )

не работает, если _ptr не является типом указателя (и NULL - это константа нулевого указателя, которая включает в себя преобразование в void*, она может работать, если NULL - это просто целочисленная константа со значением 0 даже если _ptr не имеет типа указателя).

Если _ptr имеет тип указателя, if (_ptr != NULL ) сравнивает _ptr с нулевым указателем. Simples.

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

если он не вызывает поведение undefined, интерпретирует байты sizeof (void*), начиная с адреса &_ptr, как void* и сравнивает результат этой переинтерпретации с нулевым указателем типа void*.

Он мог бы вести себя иначе, если _ptr - значение типа указателя с другим представлением, чем void*.

Он работает, если _ptr не относится к типу указателя.

Во всех разумных ситуациях, однако, это был бы более сложный способ сказать

if ((void*)_ptr != NULL)

Ответ 4

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

Эта проверка также работает там, где _ptr не является типом указателя, например. если _ptr был uintptr_t или что-то еще. В этом случае простое сравнение _ptr != NULL может не обрабатывать системы, где значения нулевого указателя не имеют представления "все ноль".

Конечно, чтение целого числа как указателя не переносимо, так что этот код обрабатывает один набор проблем для другого набора проблем.

Ответ 5

*((void **) &(_ptr)

выражение выполняет переинтерпретацию сырой памяти области памяти, занятой объектом _ptr. Первые sizeof(void *) байты интерпретируются как объект типа void *. Между тем сам объект _ptr может иметь абсолютно любой тип. Естественно предположить, что он предназначен для объекта того же размера, что и void * (или большего размера).

Например, _ptr может быть объектом некоторого целочисленного типа соответствующего размера. Очевидно, что в этом случае if (_ptr == NULL) может просто отказаться от компиляции в реализации, которая определяет NULL как (void *) 0.

Ответ 6

Если тип _ptr имеет void*, тогда код нарушает строгие правила псевдонимов и имеет поведение undefined:

Объект должен иметь сохраненное значение, доступное только с помощью значения lvalue выражение, которое имеет один из следующих типов: 76)

- совместимый тип с эффективным типом объекта,

- квалифицированная версия типа совместимый с эффективным типом объекта,

- тип, который является подписанный или неподписанный тип, соответствующий эффективному типу object - тип, который является подписанным или неподписанным типом, соответствующим квалифицированный вариант эффективного типа объекта,

- anaggregate или тип объединения, который включает один из вышеупомянутых типов среди его членов (в том числе, рекурсивно, сообщено о суммировании или содержащее объединение), или

- тип символа.

В код _ptr открывается через lvalue типа void*, который совместим только с самим собой, поэтому ни одно из указанных выше условий не является истинным.

Есть хороший шанс, что он работает как _ptr != NULL, но использование такого кода по-прежнему является ужасной практикой.