I'm reading a book called 'crafting interpreters' , and I saw a code snippet like this The function is used to grow the size of a dynamic array.
#define GROW_ARRAY(type, pointer, oldCount, newCount) \
(type*)reallocate(pointer, sizeof(type)*(oldCount), \
sizeof(type) * (newCount))
//size_t : 无符号整型,表示对象的大小和数组的index
void* reallocate(void* pointer, size_t oldSize, size_t newSize);
Why use a macro to call a function instead of calling the function directly? What are the benefits and drawbacks?
In this case, it's to introduce type safety.
The following code has an error, but the compiler doesn't catch it.
A *p;
A *q = reallocate( p, i * sizeof( B ), j * sizeof( B ) );
The following code has a different error, but the compiler doesn't catch this one either.
A *p;
B *q = reallocate( p, i * sizeof *p, j * sizeof *p );
It's impossible to make the first error using the macro, and the compiler catches instances of the second error when using the macro.
Also, the call is much simpler using the macro.
GROW_ARRAY( A, p, i, j )
Demo on Compiler Explorer
#include <stdlib.h>
void* reallocate(void* pointer, size_t oldSize, size_t newSize);
#define GROW_ARRAY(type, pointer, oldCount, newCount) \
(type*)reallocate(pointer, sizeof(type)*(oldCount), \
sizeof(type) * (newCount));
typedef int A;
typedef double B;
int main( void ) {
int i = 2;
int j = 4;
A *p = NULL; // Whatever. We're not actually running this.
{
// This error isn't caught.
A *q = reallocate( p, i * sizeof( B ), j * sizeof( B ) );
}
{
// This different error isn't caught.
B *q = reallocate( p, i * sizeof *p, j * sizeof *p );
}
{
// The same error is caught here.
B *q = GROW_ARRAY( A, p, i, j );
}
}
<source>:5:55: warning: backslash and newline separated by space
5 | #define GROW_ARRAY(type, pointer, oldCount, newCount) \
<source>: In function 'main':
<source>:6:9: error: initialization of 'B *' {aka 'double *'} from incompatible pointer type 'A *' {aka 'int *'} [-Wincompatible-pointer-types]
6 | (type*)reallocate(pointer, sizeof(type)*(oldCount), \
| ^
<source>:29:14: note: in expansion of macro 'GROW_ARRAY'
29 | B *q = GROW_ARRAY( A, p, i, j );
| ^~~~~~~~~~
Note that improvements can be made to the macro, and using the macro might introduce other problems. The Question asks about the purpose of the macro, and this Answer limits itself to addressing that.