Capture _Line_ and _File_ Without #Define

Capture __LINE__ and __FILE__ without #define

Actually the preprocessor is the only choice when you want to work with line numbers and filenames.

For the compiler it's not possible to use line numbers and filenames as arguments for function calls (or storing them in a variable).

In my company we had the exactly same issue with logging. We ended up with an external script scanning the source files and then building proper functions to call.

is there any way to get debug info like __FILE__ without using macro function in c/c++?

As far as __FILE__ and __LINE__ is concerned, C++20 introduced std::source_location for this. There is no equivalent non-macro based solution in prior C++ standards.

As far as a non-macro logging solution overall, the most common approach involves implementing the logging function as a variadic template with a parameter pack, that ends up formatting the log message, from its parameters.

Lazy __FILE__ and __LINE__ Population

Is there a way that I can accomplish this ...

Yes.

You can write a function-like macro that expands into a function call, and passes __FILE__ and __LINE__ as arguments. Since the macro is expanded at call site, that's the line which populates those macros:

#define FOO(arg) foo((arg), __FILE__, __LINE__);

... other than using a macro?

I don't think so. __FILE__ and __LINE__ are pre processor macros. Pre processing always happens before compilation.

Equivalent functionality is not implementable in standard C++ without (those) macros. A non-macro feature std::source_location has been proposed in n4519 as a Technical Specification. When passed as a default argument, it will be populated by the call site. Example from the proposal:

struct s {
source_location member = source_location::current();
int other_member;

s(source_location loc = source_location::current())
: member(loc) // values of member will be from call-site
{}

s(int blather) // values of member should be hereabouts
: other_member(blather)
{}

s(double) // values of member should be hereabouts
{}
};

Adapted for your function:

void foo(const bool is_failure, source_location loc = source_location::current());

Until (and unless) this feature is incorporated into the standard, you can rely on either a macro, or implementation specific features such as __builtin_LINE and__builtin_FILE in GCC that make it possible to implement std::source_location or equivalent.

Passing the caller __FILE__ __LINE__ to a function without using macro

So, you're looking to do logging (or something) with file & line info, and you would rather not use macros, right?

At the end of the day, it simply can't be done in C++. No matter what mechanism you chose -- be that inline functions, templates, default parameters, or something else -- if you don't use a macro, you'll simply end up with the filename & linenumber of the logging function, rather than the call point.

Use macros. This is one place where they are really not replaceable.

EDIT:

Even the C++ FAQ says that macros are sometimes the lesser of two evils.

EDIT2:

As Nathon says in the comments below, in cases where you do use macros, it's best to be explicit about it. Give your macros macro-y names, like COMMIT() rather than Commit(). This will make it clear to maintainers & debuggers that there's a macro call going on, and it should help in most cases to avoid collisions. Both good things.

__FILE__, __LINE__, and __FUNCTION__ usage in C++

__FUNCTION__ is non standard, __func__ exists in C99 / C++11. The others (__LINE__ and __FILE__) are just fine.

It will always report the right file and line (and function if you choose to use __FUNCTION__/__func__). Optimization is a non-factor since it is a compile time macro expansion; it will never affect performance in any way.

Will the pointer to __FILE__ remain valid after moving out of scope?

__FILE__ expands to a normal string literal. So as long as you are only reading it, you can just use a const char* like

const char *filename = __FILE__;

As string literals have static storage duration, the pointer will remain valid throughout the whole program.

If you want something modifiable, you need a copy and manage its lifetime yourself.

For a complete list of predefined standard macros and information about what they expand too, have a look at the "Predefined macros" section on this documentation page.

As @Keith Thompson correctly pointed out in a comment, different expansions of __FILE__ may or may not yield the same address, that is:

const char *f1 = __FILE__;
const char *f2 = __FILE__;
assert(f1 == f2); // May or may not fire

I am not sure when that would bite you, but it's good to know I guess.

Do __LINE__ __FILE__ equivalents exist in C#?

It is uglier, but you can do something like this in C# using the StackTrace and StackFrame classes:

StackTrace st = new StackTrace(new StackFrame(true));
Console.WriteLine(" Stack trace for current level: {0}", st.ToString());
StackFrame sf = st.GetFrame(0);
Console.WriteLine(" File: {0}", sf.GetFileName());
Console.WriteLine(" Method: {0}", sf.GetMethod().Name);
Console.WriteLine(" Line Number: {0}", sf.GetFileLineNumber());
Console.WriteLine(" Column Number: {0}", sf.GetFileColumnNumber());

Of course, this comes with some overhead.

How do I get the path and name of the file that is currently executing?

p1.py:

execfile("p2.py")

p2.py:

import inspect, os
print (inspect.getfile(inspect.currentframe())) # script filename (usually with path)
print (os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe())))) # script directory

Function to print the file name of the file that is calling the function

You can do it by first reaching back through the interpreter's stack using the inspect module and retrieving the name of the path to caller's file, and then extracting the file's name from that (which is very easy using the pathlib module).

main.py:

from functions import log

log('message')

functions.py:

import inspect
from pathlib import Path

def log(text):
caller_path = Path(inspect.stack()[1][1])
print(f'{caller_path.name}: {text}')


Related Topics



Leave a reply



Submit