Почему malloc использовался таким образом? - PullRequest
1 голос
/ 06 февраля 2012

Я работаю над кодом, который я запросил у исследовательской группы.Я пытаюсь понять код, однако они использовали malloc странным образом.здесь;

в заголовочном файле;

 #define ERROR_OUTPUT stderr
 #define FAILIF(b) {   \
   if (b) {  \
       fprintf(ERROR_OUTPUT, "FAILIF triggered on line %d, file %s. Memory allocated: %lld\n",  \
       __LINE__, __FILE__, totalAllocatedMemory); exit(1); \
   } \
  }
 #define MALLOC(amount) \ 
   ( (amount > 0) ? totalAllocatedMemory += amount, malloc(amount) : NULL)

в файле cpp;

 double *memRatiosForNNStructs = NULL;
 double *listOfRadii = NULL;
 nRadii = 1;
 FAILIF(NULL == (memRatiosForNNStructs = (double*)MALLOC(nRadii * sizeof(double))));

Насколько я понимаю, определение MALLOC означает, что они определены следующим образом:1009 *

if(amount>0) // which is true; at least in this case
{
   totalAllocatedMemory = totalAllocatedMemory + amount; // sounds reasonable
   malloc(amount)  // What?? This will leak memory...
}
else
{
   NULL; // Do nothing? I guess that's fine
}

Есть ли что-то, что я здесь упускаю?Или они просто совершили (наивную) ошибку?

Ответы [ 4 ]

8 голосов
/ 06 февраля 2012

Третий фрагмент кода, который у вас есть, не эквивалентен.Обратите внимание на использование оператора запятой :

#define MALLOC(amount) \
    ( (amount > 0) ? totalAllocatedMemory += amount, malloc(amount) : NULL)  
                                                   ^
                                                  N.B.!

Оператор запятой принимает два аргумента, оценивает и отбрасывает первое выражение, затем оценивает и возвращает второе выражение.

троичный условный оператор , используемый таким образом

a = ((b)?(c:d))

эквивалентен этому

if(b) {
    a = c;
}
else {
    a = d;
}

Оператор запятой, используемый таким образом

e = f, g;

эквивалентно этому

f;
e = g;

Так что если у вас есть

a = ((b)?(f,g:d))

, то это эквивалентно

if(b) {
    f;
    a = g;
}
else {
    a = d;
}

В коде, указанном в вашем исходном сообщении,макрос MALLOC должен использоваться следующим образом:

memRatiosForNNStructs = (double*)MALLOC(nRadii * sizeof(double));

, что эквивалентно этому:

   // First operand of ternary conditional
if(nRadii * sizeof(double) > 0)
{
    // Second  operand of ternary conditional

    // First expression of the comma operator
    totalAllocatedMemory += nRadii * sizeof(double));
    // Second expression of the comma operator
    memRatiosForNNStructs = (double*)malloc(nRadii * sizeof(double));
}
else
{
    // Third operand of ternary conditional
    memRatiosForNNStructs = (double*)NULL;
}

Честно говоря, это может быть достигнуто как функция в C безпотеря общности:

void* my_malloc(unsigned int amount)
{
    if(amount > 0) {
        // I assume this is a global variable
        totalAllocatedMemory = totalAllocatedMemory + amount;
        return  malloc(amount);
    }
    else {
        return NULL;
    } 
}

memRatiosForNNStructs = (double*)my_malloc(nRadii * sizeof(double));

Так что я не уверен, какой смысл даже реализовывать его как труднодоступный макрос.

3 голосов
/ 06 февраля 2012

Вы имеете дело с оператором запятой , который оценивает каждый операнд по порядку и возвращает возвращаемое значение последнего операнда. Таким образом, a + b, malloc(n) сначала оценивает a + b, затем malloc(n), а затем возвращает результат последнего. Таким образом, тип возвращаемого значения всего троичного условного выражения: void *.

Наилучшим приближением к троичному выражению является функция:

void * MALLOC(unsigned int n) {
   if (n > 0) {
      totalAllocatedMemory += n;
      return malloc(n);
   } else {
      return NULL;
   }
}
1 голос
/ 06 февраля 2012

Макрос MALLOC не совсем совпадает с вашим расширением.

Тернарный оператор вернет указатель, возвращенный при вызове malloc в случае, если условие истинно, и нулевой указатель в случае, если условие ложно.

Пока вы присваиваете результат троичного оператора переменной, нет утечки памяти.

1 голос
/ 06 февраля 2012

Они используют запутанную комбинацию троичного оператора и оператора запятой.

Имейте в виду, что:

  • троичный оператор вычисляет свой первый операнд и возвращает второйесли первое истинно, в противном случае третье;
  • оператор запятой вычисляет оба своих операнда и возвращает второй.

Таким образом, если amount>0, выражение вернет totalAllocatedMemory += amount, malloc(amount);так как оператор запятой выполняет оба выражения, но возвращает только второе, окончательное возвращаемое значение выражения является значением из malloc.

. Тем не менее, этот уродливый макрос был бы намного понятнее (и без производительностипотеря), если бы это была встроенная функция.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...