123

出于调试目的,我可以在C /C++ 编译器中获取行号吗?(某些编译器的标准方式或特定方式)

例如

if(!Logical)
    printf("Not logical value at line number %d \n",LineNumber);
    // How to get LineNumber without writing it by my hand?(dynamic compilation)
4

10 回答 10

203

您应该使用预处理器宏__LINE____FILE__. 它们是预定义的宏,是 C/C++ 标准的一部分。在预处理期间,它们分别被一个常量字符串替换,该字符串包含一个表示当前行号的整数和当前文件名。

其他预处理器变量:

  • __func__: 函数名(这是C99的一部分,并非所有 C++ 编译器都支持它)
  • __DATE__: 形式为“Mmm dd yyyy”的字符串
  • __TIME__: 形式为“hh:mm:ss”的字符串

您的代码将是:

if(!Logical)
  printf("Not logical value at line number %d in file %s\n", __LINE__, __FILE__);
于 2010-05-17T14:27:31.933 回答
66

作为 C++ 标准的一部分,您可以使用一些预定义的宏。C++ 标准的第 16.8 节定义了__LINE__宏。

__LINE__当前源行的行号(十进制常量)。
__FILE__:源文件的假定名称(字符串文字)。
__DATE__:源文件的翻译日期(字符串文字...)
__TIME__:源文件的翻译时间(字符串文字...)
__STDC__:是否__STDC__预定义
__cplusplus:名称__cplusplus定义为值 199711L 时编译一个 C++ 翻译单元

所以你的代码是:

if(!Logical)
  printf("Not logical value at line number %d \n",__LINE__);
于 2010-05-17T14:27:28.970 回答
19

您可以使用与printf()具有相同行为的宏,除了它还包含调试信息,例如函数名称、类和行号:

#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)

这些宏的行为应该与printf()相同,同时包含类似 java stacktrace 的信息。这是一个主要的示例:

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

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

这导致以下输出:

main(main.cpp:11) 之前 exampleMethod()...
exampleMethod(main.cpp:7) printf() 语法: string = foobar, int = 42
main(main.cpp:13) 成功!

于 2014-11-07T21:15:57.840 回答
11

使用__LINE__(即双下划线 LINE 双下划线),预处理器会将其替换为遇到的行号。

于 2010-05-17T14:27:30.033 回答
10

C++20 提供了一种通过使用std::source_location来实现此目的的新方法。这目前可以在 gcc 和 clang 中访问,std::experimental::source_location#include <experimental/source_location>.

像这样的宏的问题__LINE__是,如果您想创建例如一个输出当前行号和消息的日志记录函数,您总是必须__LINE__作为函数参数传递,因为它在调用站点被扩展。像这样的东西:

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

将始终输出函数声明的行,而不是log实际调用的行。另一方面,std::source_location你可以这样写:

#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;
}

在这里,loc用指向log被调用位置的行号进行初始化。 你可以在这里在线尝试。

于 2019-10-25T09:43:16.453 回答
9

结帐__FILE____LINE__

于 2010-05-17T14:27:44.460 回答
5

对于那些可能需要它的人,一个“FILE_LINE”宏可以轻松打印文件和行:

#define STRINGIZING(x) #x
#define STR(x) STRINGIZING(x)
#define FILE_LINE __FILE__ ":" STR(__LINE__)
于 2020-05-14T09:37:09.217 回答
4

尝试__FILE____LINE__
您可能还会发现__DATE____TIME__有用。
尽管除非您必须在客户端调试程序并因此需要记录这些信息,否则您应该使用正常调试。

于 2010-05-17T15:24:07.143 回答
1

由于我现在也面临这个问题,我无法为这里提出的不同但有效的问题添加答案,我将为以下问题提供一个示例解决方案:仅获取调用函数的行号C++ 使用模板。

背景:在 C++ 中,可以使用非类型整数值作为模板参数。这与将数据类型用作模板参数的典型用法不同。所以想法是使用这样的整数值进行函数调用。

#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;
}

输出:

该函数已在行号调用:0

该函数已在第 16 行调用

这里要提到的一件事是,在 C++11 标准中,可以为使用模板的函数提供默认模板值。在 C++11 之前,非类型参数的默认值似乎只适用于类模板参数。因此,在 C++11 中,不需要像上面那样重复函数定义。在 C++11 中,具有 const char* 模板参数也是有效的,但不能将它们与此处__FILE__提到的或__func__如前所述的文字一起使用。

所以最后,如果你使用 C++ 或 C++11,这可能是一个非常有趣的替代方案,而不是使用宏来获取调用行。

于 2016-02-09T20:51:22.510 回答
1

使用__LINE__,但它的类型是什么?

LINE当前源代码行(一个整数常量)的假定行号(在当前源文件中)。

作为一个整数常量,代码通常可以假设值是__LINE__ <= INT_MAX,类型是 int

要在 C 中打印,printf()需要匹配说明符:"%d". 在带有cout.

迂腐的担忧:如果行号超过INT_MAX1(在 16-bit 中可以想象到int),希望编译器会产生警告。例子:

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

或者,代码可以强制使用更广泛的类型来阻止此类警告。

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__));

避免printf()

为了避免所有整数限制:stringify。代码无需调用即可直接打印printf():在错误处理中避免的一件好事2

#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拥有如此大的文件当然是糟糕的编程实践,但机器生成的代码可能会很高。

2在调试中,有时代码根本无法按预期工作。*printf()与简单的fputs().

于 2020-02-19T21:07:32.193 回答