处理代码中的__FILE__和__LINE__引用?
有没有办法获取C / C ++预处理器或者模板或者类似的东西来处理/散列__FILE__和__LINE__以及其他一些外部输入(例如,将内部版本号转换成单个短号,可以在日志或者错误消息中引用)?
(目的是当客户在错误报告中引用它时,能够在需要时将其反转(如果有损,返回候选列表)。)
解决方案
好吧,如果我们要向用户显示消息(而不是让系统显示崩溃地址或者功能),则没有什么可以阻止我们准确显示我们想要的内容。
例如:
typedef union ErrorCode { struct { unsigned int file: 15; unsigned int line: 12; /* Better than 5 bits, still not great Thanks commenters!! */ unsigned int build: 5; } bits; unsigned int code; } ErrorCode; unsigned int buildErrorCodes(const char *file, int line, int build) { ErrorCode code; code.bits.line=line & ((1<<12) - 1); code.bits.build=build & ((1<< 5) - 1); code.bits.file=some_hash_function(file) & ((1<<15) - 1); return code.code; }
我们可以将其用作
buildErrorCodes(__FILE__, __LINE__, BUILD_CODE)
并以十六进制形式输出。解码起来并不难...
(编辑-注释者是正确的,我必须为指定行号指定5位。要记住,模数是4096. 但是,带有错误消息的行不太可能发生冲突。用于构建的5位仍然是很好的模数32意味着仅32个版本可能非常出色,并且错误仍然在同一行发生。)
我们将必须使用函数来执行哈希操作,并根据__LINE__和__FILE__创建代码,因为C预处理器无法执行此类复杂的任务。
无论如何,我们可以从本文中获得启发,看看是否有其他解决方案更适合情况。
好吧...我们可以使用类似以下内容的方法:
((*(int*)__FILE__ && 0xFFFF0000) | version << 8 | __LINE__ )
它不会是完全独特的,但可能会满足需求。可以将这些OR更改为+,这在某些情况下可能会更好。
自然,如果我们可以实际创建哈希码,则可能需要这样做。
我在我的一个项目中需要串行值,并通过制作专门针对__LINE__和__FILE__的模板来获得它们,从而得到一个int并为其输入生成(作为编译时输出到stdout)模板特化导致该模板的行号。这些是第一次通过编译器收集的,然后转储到代码文件中,然后再次编译程序。到那时,使用模板的每个位置都有一个不同的数字。
(在D中完成,因此在C ++中可能无法实现)
template Serial(char[] file, int line) { prgams(msg, "template Serial(char[] file : \"~file~"\", int line : "~line.stringof~")" "{const int Serial = __LINE__;"); const int Serial = -1; }
一个更简单的解决方案是保留全局静态"错误位置"变量。
#ifdef DEBUG #define trace_here(version) printf("[%d]%s:%d {%d}\n", version, __FILE__, __LINE__, errloc++); #else #define trace_here(version) printf("{%lu}\n", version<<16|errloc++); #endif
或者不使用printf。每次穿过跟踪点时,只需增加errloc。然后,我们可以很容易地将值与调试版本吐出的行/编号/版本相关联。
我们需要包括版本或者内部版本号,因为这些错误位置可能随任何内部版本而改变。
如果我们无法重现代码路径,则无法正常工作。
__FILE__是指向程序常量段的指针。如果输出该常数与其他常数之间的差,则应得到与任何重定位无关的结果,等等:
extern const char g_DebugAnchor; #define FILE_STR_OFFSET (__FILE__ - &g_DebugAnchor)
然后,我们可以报告该错误,或者以某种方式将其与行号结合起来,等等。FILE_STR_OFFSET的中间位可能是最有趣的。