Reputation: 1013
I'm working on a code I requested from a researching team. I'm trying to understand the code, however, they used malloc in a strange way. here;
in the header file;
#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)
in the cpp file;
double *memRatiosForNNStructs = NULL;
double *listOfRadii = NULL;
nRadii = 1;
FAILIF(NULL == (memRatiosForNNStructs = (double*)MALLOC(nRadii * sizeof(double))));
From my understanding, the MALLOC that they defined means the following;
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
}
Is there something that I'm missing here? Or did they just make a (naive) mistake?
Upvotes: 1
Views: 353
Reputation: 52159
The third code snippet you have is not equivalent. Notice the use of the comma operator:
#define MALLOC(amount) \
( (amount > 0) ? totalAllocatedMemory += amount, malloc(amount) : NULL)
^
N.B.!
The comma operator takes two arguments, evaluates and discards the first expression, then evaluates and returns the second expression.
The ternary conditional operator used this way
a = ((b)?(c:d))
is equivalent to this
if(b) {
a = c;
}
else {
a = d;
}
The comma operator used this way
e = f, g;
is equivalent to this
f;
e = g;
So if you have
a = ((b)?(f,g:d))
then that is equivalent to
if(b) {
f;
a = g;
}
else {
a = d;
}
In the code provided in your original post, the MALLOC
macro is to be used like this:
memRatiosForNNStructs = (double*)MALLOC(nRadii * sizeof(double));
which is equivalent to this:
// 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;
}
Honestly though, this could be achieved as a function in C with no loss of generality:
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));
So I'm not sure what's the point of even implementing it as a hard-to-read macro.
Upvotes: 8
Reputation: 477060
You're dealing with the comma operator, which evaluates each operand in order and returns the return value of the last operand. So a + b, malloc(n)
first evaluates a + b
, then malloc(n)
, and then returns the result of the latter. So the return type of the entire ternary conditional expression is void *
.
The best approximation to the ternary expression is a function:
void * MALLOC(unsigned int n) {
if (n > 0) {
totalAllocatedMemory += n;
return malloc(n);
} else {
return NULL;
}
}
Upvotes: 3
Reputation: 32576
The MALLOC
macro is not quite the same as your expansion.
The ternary operator will return the pointer returned by the call to malloc
in the case that the condition is true, and a NULL pointer in the case that the condition is false.
As long as you assign the result of the ternary operator to a vairable there's no memeory leak.
Upvotes: 1
Reputation: 126797
They are using a confusing combination of the ternary operator and of the comma operator.
Keep in mind that:
Thus, if amount>0
, the expression will return totalAllocatedMemory += amount, malloc(amount)
; since the comma operator executes both expressions but returns only the second, the final return value of the expression is the one from the malloc
.
Still, that ugly macro would have been much clearer (and with no performance loss) if it were an inline function.
Upvotes: 1