5

I'd like to produce a static string of the form "example.cpp:34" with the preprocessor, but the __FILE__ macro will expand to "lib/example/example.cpp" and __LINE__ expands to 34 as an integer. Can I construct the desired string with the preprocessor? GCC extentions are ok.

Edit The most important part here is that I want a static C-style string, so I can't use the basename function. I'm wondering if there's some way in the preprocessor to replicate that functionality, possibly with a boost extension?

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
pythonic metaphor
  • 10,296
  • 18
  • 68
  • 110

4 Answers4

3

You can take advantage of the fact that adjacent string literals are concatenated:

#define STRINGIFY(s) #s
#define FILELINE(line) __FILE__ ":" str(line)

Then use it like FILELINE(__LINE__). I don't do this very often so there may be a better way than having to pass the __LINE__ macro. It works for me anyway, testing with:

#include <iostream>

#define str(s) #s
#define FILELINE(line) __FILE__ ":" str(line)

int main(int argc, const char* argv[])
{
  std::cout << FILELINE(__LINE__) << std::endl;
  return 0;
}

I get:

main.cpp:9
Joseph Mansfield
  • 108,238
  • 20
  • 242
  • 324
0

You should be able to just use basename() as __FILE__ expands to a const C string

__FILE__ This macro expands to the name of the current input file, in the form of a C string constant.

printf ("%s:%d\n", basename(__FILE__), __LINE__);
iabdalkader
  • 17,009
  • 4
  • 47
  • 74
0

I don't know of a way to get the basename, but oyther than that you can used the stringification preprocessor operator '#', like:

#define M__(x,y) x ":" #y
#define M_(x,y) M__(x, y)
#define M M_(__FILE__, __LINE__)

Now M will expand to "lib/example/example.cpp:34" (given you put it in that file on that line, ofc :))

chill
  • 16,470
  • 2
  • 40
  • 44
0

Well, not only preprocessor has to be used - but it won't be seen to the end user.

When you want BASENAME() to be used in some file - use this header file basename.h:

// basename.h
#include <string.h>

static size_t basename_start_calc(const char* filename)
{
    const char* base = strrchr(filename, '/');
    return base ? (base - filename + 1) : 0;
}
static inline size_t basename_start(const char* filename)
{
    static size_t retval = basename_start_calc(filename);
    return retval;
}
#define STR_(t) #t
#define STR(t) STR_(t)
#define BASENAME()  ((__FILE__ ":" STR(__LINE__)) + basename_start(__FILE__))

An ideone example here.

basename_start(__FILE__) will be evaluated only once for the given source file. Unfortunately you can't use this solution in header files - only in source files. You can change it, so it can be used everywhere - but then start of baseline for the given filename will be calculated every time. Just use in BASENAME() basename_start_calc(__FILE__) instead of basename_start(__FILE__)...

I believe this is best you can have automatically.

Of course you can define by hand in every file macro:

#define BASENAME()  ("somefile.cpp:" STR(__LINE__))

but I am not sure this is what you wanted....

PiotrNycz
  • 23,099
  • 7
  • 66
  • 112