处理代码中的__FILE__和__LINE__引用?

时间:2020-03-06 14:48:43  来源:igfitidea点击:

有没有办法获取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的中间位可能是最有趣的。