ChatGPT解决这个技术问题 Extra ChatGPT

In the sake of debugging purposes, can I get the line number in C/C++ compilers? (standard way or specific ways for certain compilers)

e.g

if(!Logical)
    printf("Not logical value at line number %d \n",LineNumber);
    // How to get LineNumber without writing it by my hand?(dynamic compilation)
@Lucas: Some of us prefer not to mess with debuggers. This kind of "poor person's assert statement" is sometimes more clear because it's a permanent part of the code, and enduring documentation of things that should be true about the state of the computation.
@Lucas: Debuggers are also less than useful for intermittent problems in long-running programs, or for collecting information about problems in software deployed at client sites. In these cases, the only option is for the program to log as much information about the state of the program as possible, for later analysis.
@Lucas And debuggers don't work so well on some embedded systems to get this information.

J
Julien Hoarau

You should use the preprocessor macro __LINE__ and __FILE__. They are predefined macros and part of the C/C++ standard. During preprocessing, they are replaced respectively by a constant string holding an integer representing the current line number and by the current file name.

Others preprocessor variables :

__func__ : function name (this is part of C99, not all C++ compilers support it)

__DATE__ : a string of form "Mmm dd yyyy"

__TIME__ : a string of form "hh:mm:ss"

Your code will be :

if(!Logical)
  printf("Not logical value at line number %d in file %s\n", __LINE__, __FILE__);

C99 uses __func__ rather than __FUNCTION__, which AFAIK is partially deprecated. The difference can break your code, because __func__ cannot be used for C's constant string concatenation.
Reference from GCC manual: "__FUNCTION__ and __PRETTY_FUNCTION__ were treated as string literals; they could be used to initialize char arrays, and they could be concatenated with other string literals. GCC 3.4 and later treat them as variables, like __func__. In C++, __FUNCTION__ and __PRETTY_FUNCTION__ have always been variables."
Is there a way to get the line number as a string, same as the file name? I'd like the preprocessor to give me e.g. the string literal "22" instead of integer 22.
@sep332 Yes, but the cpp is a strange beast, so it must be done in two steps with macro arguments. #define S1(N) #N #define S2(N) S1(N) #define LINESTR S2(__LINE__) . See c-faq.com/ansi/stringize.html
Strictly saying, __func__ is not a macro, it's an implicitly declared variable.
B
Brian R. Bondy

As part of the C++ standard there exists some pre-defined macros that you can use. Section 16.8 of the C++ standard defines amongst other things, the __LINE__ macro.

__LINE__: The line number of the current source line (a decimal constant). __FILE__: The presumed name of the source file (a character string literal). __DATE__: The date of translation of the source file (a character string literal...) __TIME__: The time of translation of the source file (a character string literal...) __STDC__: Whether__STDC__ is predefined __cplusplus: The name __cplusplus is defined to the value 199711L when compiling a C ++ translation unit

So your code would be:

if(!Logical)
  printf("Not logical value at line number %d \n",__LINE__);

B
BullyWiiPlaza

You could use a macro with the same behavior as printf(), except that it also includes debug information such as function name, class, and line number:

#include <cstdio>  //needed for printf
#define print(a, args...) printf("%s(%s:%d) " a,  __func__,__FILE__, __LINE__, ##args)
#define println(a, args...) print(a "\n", ##args)

These macros should behave identically to printf(), while including java stacktrace-like information. Here's an example main:

void exampleMethod() {
    println("printf() syntax: string = %s, int = %d", "foobar", 42);
}

int main(int argc, char** argv) {
    print("Before exampleMethod()...\n");
    exampleMethod();
    println("Success!");
}

Which results in the following output:

main(main.cpp:11) Before exampleMethod()... exampleMethod(main.cpp:7) printf() syntax: string = foobar, int = 42 main(main.cpp:13) Success!


for c development, you would change the #include to <stdio.h>
printf is not async-signal-safe. So this macros can not be used in signal handlers.
s
sirain

C++20 offers a new way to achieve this by using std::source_location. This is currently accessible in gcc an clang as std::experimental::source_location with #include <experimental/source_location>.

The problem with macros like __LINE__ is that if you want to create for example a logging function that outputs the current line number along with a message, you always have to pass __LINE__ as a function argument, because it is expanded at the call site. Something like this:

void log(const std::string msg) {
    std::cout << __LINE__ << " " << msg << std::endl;
}

Will always output the line of the function declaration and not the line where log was actually called from. On the other hand, with std::source_location you can write something like this:

#include <experimental/source_location>
using std::experimental::source_location;

void log(const std::string msg, const source_location loc = source_location::current())
{
    std::cout << loc.line() << " " << msg << std::endl;
}

Here, loc is initialized with the line number pointing to the location where log was called. You can try it online here.


u
user229044

Use __LINE__ (that's double-underscore LINE double-underscore), the preprocessor will replace it with the line number on which it is encountered.


A
Anton

Checkout __FILE__ and __LINE__ macros


S
Sanctus2099

Try __FILE__ and __LINE__.
You might also find __DATE__ and __TIME__ useful.
Though unless you have to debug a program on the clientside and thus need to log these informations you should use normal debugging.


Why was I voted down on this and why did mmyers edit my post?
@Sanctus2099: It was edited, because Markdown transformed your double underscores to display FILE and LINE in bold font (don't you check how your answer looks like?). Another point might be (at least it looks to me this way now) that you gave an answer 1 hour after an already correct answer was given, so you added no value.
Double underscore is markup syntax for bold. In order to properly display double underscores, you must escape them (like this: \_\_) or use backticks to mark them as raw code (like this: `__`). @mmyers attempted to help, but he only escaped one of the underscores, and thus you were left with the markup syntax for italics. Downvotes are a bit harsh here, though, I agree.
Okay I didn't realize the thing about double underscores turning text into bold and I had to go and didn't have time to look at how my answer was looking. I do understand now. Even if my answer was an hour late it was still a good answer. It didn't add any value but it wasn't wrong either so no reason for downvote. That's what you get for trying to help...
@Sanctus2099 Some people are quick to down-vote, that's why it's important to make sure your answer is correct. In this case, you posted a wrong answer and left it unedited for 4 hours. You've got nobody to blame but yourself.
c
clarkttfu

For those who might need it, a "FILE_LINE" macro to easily print file and line:

#define STRINGIZING(x) #x
#define STR(x) STRINGIZING(x)
#define FILE_LINE __FILE__ ":" STR(__LINE__)

C
Community

Since i'm also facing this problem now and i cannot add an answer to a different but also valid question asked here, i'll provide an example solution for the problem of: getting only the line number of where the function has been called in C++ using templates.

Background: in C++ one can use non-type integer values as a template argument. This is different than the typical usage of data types as template arguments. So the idea is to use such integer values for a function call.

#include <iostream>

class Test{
    public:
        template<unsigned int L>
        int test(){
            std::cout << "the function has been called at line number: " << L << std::endl;
            return 0;
        }
        int test(){ return this->test<0>(); }
};

int main(int argc, char **argv){
    Test t;
    t.test();
    t.test<__LINE__>();
    return 0;
}

Output:

the function has been called at line number: 0 the function has been called at line number: 16

One thing to mention here is that in C++11 Standard it's possible to give default template values for functions using template. In pre C++11 default values for non-type arguments seem to only work for class template arguments. Thus, in C++11, there would be no need to have duplicate function definitions as above. In C++11 its also valid to have const char* template arguments but its not possible to use them with literals like __FILE__ or __func__ as mentioned here.

So in the end if you're using C++ or C++11 this might be a very interesting alternative than using macro's to get the calling line.


c
chux - Reinstate Monica

Use __LINE__, but what is its type?

LINE The presumed line number (within the current source file) of the current source line (an integer constant).

As an integer constant, code can often assume the value is __LINE__ <= INT_MAX and so the type is int.

To print in C, printf() needs the matching specifier: "%d". This is a far lesser concern in C++ with cout.

Pedantic concern: If the line number exceeds INT_MAX1 (somewhat conceivable with 16-bit int), hopefully the compiler will produce a warning. Example:

format '%d' expects argument of type 'int', but argument 2 has type 'long int' [-Wformat=]

Alternatively, code could force wider types to forestall such warnings.

printf("Not logical value at line number %ld\n", (long) __LINE__);
//or
#include <stdint.h>
printf("Not logical value at line number %jd\n", INTMAX_C(__LINE__));

Avoid printf()

To avoid all integer limitations: stringify. Code could directly print without a printf() call: a nice thing to avoid in error handling2 .

#define xstr(a) str(a)
#define str(a) #a

fprintf(stderr, "Not logical value at line number %s\n", xstr(__LINE__));
fputs("Not logical value at line number " xstr(__LINE__) "\n", stderr);

1 Certainly poor programming practice to have such a large file, yet perhaps machine generated code may go high.

2 In debugging, sometimes code simply is not working as hoped. Calling complex functions like *printf() can itself incur issues vs. a simple fputs().