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
Right Justifying Output Stream in C++
How to Set Given Channel of a Cv::Mat to a Given Value Efficiently Without Changing Other Channels
G++ Linker: Force Static Linking If Static Library Exists
Why Are Pointers to a Reference Illegal in C++
What Are the Stages of Compilation of a C++ Program
#Define Sqr(X) X*X. Unexpected Answer
Std::Variant' VS. Inheritance VS. Other Ways (Performance)
Which Is Faster:If (Bool) or If(Int)
C/C++ Counting the Number of Decimals
Check Xmm Register for All Zeroes
C++ When Should We Prefer to Use a Two Chained Static_Cast Over Reinterpret_Cast
Opencv Edge/Border Detection Based on Color
What Modern C++ Libraries Should Be in My Toolbox
Finding Memory Leaks in a C++ Application with Visual Studio