C/C + + 行号

为了调试的目的,我可以得到行号在 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)
136604 次浏览

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

__LINE__: 当前源行的行号(一个小数 常数)。
__FILE__: 源文件的推定名称(一个字符串 字面意思)。
__DATE__: 源文件的翻译日期(一个字符串 字面意思...)
源文件(一个字符串)的翻译时间 字面意思...)
__STDC__: __STDC__是否是预定义的
时,名称 __cplusplus定义为值199711L 编译一个 C + + 翻译单元

所以你的代码应该是:

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

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

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

其他预处理变量:

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

您的代码将是:

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

检查 __FILE____LINE__

试试 __FILE____LINE__
您可能还会发现 __DATE____TIME__很有用。
不过,除非您必须在客户端调试程序,因此需要记录这些信息,否则应该使用普通调试。

您可以使用具有与 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 堆栈跟踪的信息:

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) Before exampleMethod () ...
ExampleMethod (main.cpp: 7) printf ()语法: string = foobar,int = 42
Main (main.cpp: 13)成功!

因为我现在也面临这个问题,我不能添加一个不同的答案,但也有效的问题问 给你, 我将提供一个例子来解决这个问题: 使用模板只获取函数在 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标准中,可以为使用模板的函数提供默认模板值。在 pre C + + 11中,非类型参数的默认值似乎只适用于类模板参数。因此,在 C + + 11中,不需要像上面那样有重复的函数定义。在 C + + 11中,拥有 const char * 模板参数也是有效的,但是不可能像前面提到的 给你那样将它们与 __FILE____func__这样的文字一起使用。

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

C + + 20通过使用 Source _ location提供了一种新的实现方法。这是目前可以在 gcc 的叮当作为 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;
}

在这里,使用指向调用 log的位置的行号初始化 loc你可以在网上试试。

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

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

作为 整数常数,代码通常可以假定值为 __LINE__ <= INT_MAX,因此类型为 int

要在 C 中打印,printf()需要匹配的说明符: "%d"。在使用 cout的 C + + 中,这个问题要小得多。

迂腐的担心: 如果行号超过 INT_MAX1(对于16位 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()

避免所有整数限制: 串起来。代码可以在没有 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);

当然,拥有如此大的文件的编程实践很糟糕,但是机器生成的代码可能会很高。

2 在调试中,有时代码根本就不能像预期的那样工作。与简单的 fputs()相比,调用诸如 *printf()这样的复杂函数本身可能会出现问题。

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

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