gpt4 book ai didi

c - 打印编译时保存的文件名

转载 作者:太空宇宙 更新时间:2023-11-04 06:51:36 26 4
gpt4 key购买 nike

我的目标是打印文件名而不是文件名的相对路径。我正在使用宏 TRACE() 对其进行试验。因为它们都在同一个文件中,所以我将文件名模拟为 TRACE() 的输入。所以在现实生活中,您可以说输入被替换为 __FILE__

代码:

#include <stdio.h>
#include <string.h>

#define STRINGIFY(x) #x
#define TOSTRING(x) STRINGIFY(x)

#define __FILENAME__(x) TOSTRING(strrchr(x, '\\'))

#define TRACE(s, ...) \
{ \
if (strrchr(s, '\\')) { \
static const char str[] = __FILENAME__(s) "\n\r"; \
printf(str, ##__VA_ARGS__); \
} else { \
static const char str[] = s "\n\r"; \
printf(str, ##__VA_ARGS__); \
} \
}

int main() {
TRACE("file.c");
TRACE("parent\\file.c");
return 0;
}

输出:

file.c
strrchr("parent\\file.c", '\\')

所以如果它是本地文件,它会被打印为 file.c,这很好。这意味着宏中的 ifcase 有效 :)。但是当它是另一个文件夹中的文件时,我无法“字符串化”计算 strrchr(s, '\\')。为什么?

此外,我没有看到定义中的计算有问题,因为一切都是在编译时定义的!! (这就是 if 案例起作用的原因,对吧?)

如果我从 __FILENAME__ 中删除 TOSTRING(),我会得到大量错误。因为它无法将 __FILENAME__ 的输出与 str[]

连接起来

有办法解决吗?

最佳答案

初步观察

请注意,在 C(与 C++ 相对)中,您不能使用函数调用的结果来初始化 static const char str[] 数组。如果 strrchr() 找到一个反斜杠,您可能想要打印反斜杠后面的名称。并且字符串化不会对调用 strrchr() 的结果进行字符串化。

另请注意,一般情况下,您不应创建以下划线开头的函数或变量名称。 C11 §7.1.3 Reserved identifiers说(部分):

  • All identifiers that begin with an underscore and either an uppercase letter or another underscore are always reserved for any use.
  • All identifiers that begin with an underscore are always reserved for use as identifiers with file scope in both the ordinary and tag name spaces.

另见 What does double underscore (__const) mean in C?

由于您的 TRACE 宏的第一个参数已经是一个字符串,因此应用字符串化没有太大好处 — 除非您希望在打印名称时出现双引号。

简单改编

为了或多或少地获得您想要的结果,您需要接受每次通过跟踪(或更详细的方案)时调用 strrchr() 的运行时开销用于初始化),按照以下行:

#define TRACE(s, ...) \
do { \
const char *basename = strrchr(s, '\\'); \
if (basename == 0) \
basename = s; \
else \
basename++; \
printf(basename, ## __VA_ARGS__); \
} while (0)

do { … } while (0) 成语是标准的;它允许你写:

if (something)
TRACE("hocuspocus.c: test passed\n");
else
TRACE("abracadabra.c: test failed\n");

如果您在问题中使用仅大括号表示法,则第一个 TRACE 之后的分号会使 else 成为语法错误。另见 C #define macro for debug printingWhy use apparently meaningles do { … } while (0) and if … else statements in macros?do { … } while (0) — what is it good for?

## __VA_ARGS__ 技巧很好,只要您知道它是 GCC(和 Clang,因为它与 GCC 兼容)扩展,而不是标准 C 的一部分。

您还不完全清楚您打算如何使用变量参数。看起来您可以这样做:

TRACE("some\\kibbitzer.c: value %d is out of the range [%d..%d]\n",
value, MIN_RANGE, MAX_RANGE);

文件名嵌入在格式字符串中。也许你想到了:

TRACE(__FILE__ ": value %d is out of the range [%d..%d]\n",
value, MIN_RANGE, MAX_RANGE);

那行得通; __FILE__ 是一个字符串文字,与 __func__ 不同,它是一个预定义的标识符 (static const char __func__[] = "...function name...";) .

最后(现在),考虑跟踪输出应该转到标准输出还是标准错误。很容易争论它应该进入标准错误;它(可能)不是程序常规输出的一部分。

我建议查看“调试宏”问题和答案——但我有偏见,因为我写了得分最高的答案。

减少运行时开销

您可以将运行时开销减少到对每个文件名调用 strrchr() 一次,只要您不弄乱自动变量等。如果您是使用字符串文字。

#define TRACE(s, ...) \
do { \
static const char *basename = 0;
if (basename == 0) \
{
if ((basename = strrchr(s, '\\')) == 0) \
basename = s; \
else \
basename++; \
} \
printf(basename, ## __VA_ARGS__); \
} while (0)

这会将 basename 初始化为 null;在第一次通过代码时,basename 被设置为字符串中的正确位置;此后,不再调用 strrchr()

警告:显示的代码尚未编译。

关于c - 打印编译时保存的文件名,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50348438/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com