1

I have a function for allocating memory, which has a default argument for alignment...

void* symalloc(int numbytes, int alignment=32)

I want to get file/line numbers passed in from the call location. So, I changed it to this...

void* _symalloc(int numbytes, int alignment, const char* file, int line);
#define symalloc(numbytes, alignment) _symalloc(numbytes, alignment, __FILE__, __LINE)

But now the problem is all the callers which were not passing in alignment are broken, and there are hundreds of these.

Is there some way to have this support either being passed alignment or not, and supply the file/line in either case?

James
  • 1,973
  • 1
  • 18
  • 32
  • Identifiers beginning with an underscore are reserved in the global namespace \*dub di dub\* – Swordfish May 14 '19 at 00:43
  • Can you provide default arguments for your wrapper? – XapaJIaMnu May 14 '19 at 00:44
  • How do I provide default arguments to a macro? If I make all the arguments of _symalloc have default arguments, the macro is still written to take 2 arguments not 1. – James May 14 '19 at 00:49

3 Answers3

2

Use a variadic macro and __VA_ARGS__ (C++11 and later, and often supported by earlier compilers too):

void symalloc_(const char* file, int line, int numbytes, int alignment=32);
#define symalloc(...) (symalloc(__FILE__, __LINE__, __VA_ARGS__))

Note the rearrangement of parameters so that the default argument is on the last one.

aschepler
  • 70,891
  • 9
  • 107
  • 161
0

You need to put default parameters for those other values as well, so it won't matter that some call sites do not have them:

void* _symalloc(int numbytes, int alignment = 32, const char* file = NULL, int line = 0);
Darrin Cullop
  • 1,170
  • 8
  • 14
0

It's possible with a bit of pre-processor magic (thanks to this answer)

The real trick is to work around the fact that macros cannot be overloaded. These macros works by using the arguments themselves to shift around the name of another macro (used to choose an overload) which is selected by position.

Note that the default value "32" appears inside the SYMALLOC1 macro.

#include <iostream>

void* symalloc_impl(int numbytes, int alignment, const char* file, int line){
    std::cout << file << ':' << line << "> symalloc(" << numbytes << ", " << alignment << ")\n";
    return nullptr;
}

#define SYMALLOC1(numbytes) symalloc_impl(numbytes, 32, __FILE__, __LINE__)
#define SYMALLOC2(numbytes, alignment) symalloc_impl(numbytes, alignment, __FILE__, __LINE__)
#define SYMALLOC_DISPATCH(_1,_2,NAME,...) NAME
#define symalloc(...) SYMALLOC_DISPATCH(__VA_ARGS__,SYMALLOC2,SYMALLOC1,UNUSED)(__VA_ARGS__)

int main() {

    symalloc(16);

    symalloc(64, 8);

    return 0;
}

Example output:

main.cpp:15> symalloc(16, 32)

main.cpp:17> symalloc(64, 8)

Live example here.

alter_igel
  • 6,899
  • 3
  • 21
  • 40