为什么malloc使用这种方式?

时间:2012-02-06 00:29:46

标签: c++ memory malloc

我正在研究我从研究团队请求的代码。我试图理解代码,然而,他们以一种奇怪的方式使用了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意味着以下内容;

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 个答案:

答案 0 :(得分:8)

您拥有的第三个代码段并不等效。请注意使用the comma operator

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

逗号运算符接受两个参数,计算并丢弃第一个表达式,然后计算并返回第二个表达式。

ternary conditional operator以这种方式使用

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));

所以我不确定将它作为一个难以阅读的宏实现的重点是什么。

答案 1 :(得分:3)

您正在处理逗号运算符,它按顺序计算每个操作数并返回最后一个操作数的返回值。因此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;
   }
}

答案 2 :(得分:1)

他们正在使用三元运算符和逗号运算符的混淆组合。

请记住:

  • 三元运算符计算其第一个操作数,如果第一个操作数为真则返回第二个操作数,否则返回第三个操作数;
  • 逗号运算符计算其两个操作数并返回第二个。

因此,如果amount>0,表达式将返回totalAllocatedMemory += amount, malloc(amount);由于逗号运算符执行两个表达式但仅返回第二个表达式,因此表达式的最终返回值是malloc中的值。

但是,如果它是一个内联函数,那个丑陋的宏会更清晰(并且没有性能损失)。

答案 3 :(得分:1)

MALLOC宏与您的扩展程序不完全相同。

在条件为真的情况下,三元运算符将返回由malloc调用返回的指针,如果条件为假,则返回NULL指针。

只要您将三元运算符的结果分配给可变量,就不存在任何记忆泄漏。