【问题标题】:How to get only file name in preprocessor?如何在预处理器中仅获取文件名?
【发布时间】:2011-09-13 07:31:42
【问题描述】:

我(曾经)使用__FILE____LINE__ 宏从我的代码中打印诊断消息。当您将 GCC 与 make 一起使用时,这非常有效,该文件与您在命令行中指定的一样短。我最近切换到使用 CodeLite,它在构建时使用完全限定的文件名(至少在 Windows 下)。突然间,我的诊断输出几乎不可读了。

有没有办法在预处理器中只获取文件名的文件组件?我可以接受非便携式 GCC 特定解决方案。 (我将回退到普通的__FILE__ 其他情况。)

当然,我可以通过函数传递__FILE__ 的内容并仅提取文件组件,但对于不应更改运行时行为的诊断消息,我不考虑字符串操作...

注意:我使用 GNU 使用文件名的方式。路径是文件名的集合,文件名是文件的相对或绝对标识符。文件名可以由目录组件和文件组件组成。

【问题讨论】:

  • 诊断确实会改变运行时行为(否则不会有诊断),并且是否调用一个额外的函数几乎没有什么区别,因为输出本身正在调用库函数来执行输出。
  • 打印一条诊断消息通常涉及到除了几十个字符串操作之外,还有一些不太友好的文件 I/O 操作。出于某种原因,似乎没有人担心这一点。为什么要担心添加对另一个仅影响诊断消息的无副作用函数的调用?
  • 你们说的都是对的,添加诊断不是免费的。我是这样实现的,我让它通过一个函数。我更想知道它是否存在。它肯定不是标准的,但是找到有关此的文档并不完美。 (甚至 gcc 手册也没有概述每个预定义的宏。)
  • 关于 I/O;并非每个诊断都必须打印到 STDOUT/STDERR 或文件。听说过应用程序崩溃时输出的环形缓冲区吗?例如 GNU Nana 实现了这一点。与对性能“几乎”没有影响的文件 I/O 相比。
  • 仅供参考,还有 c++ constexpr 解决方案:stackoverflow.com/a/38237385/52074

标签: gcc c-preprocessor filenames


【解决方案1】:

如果您使用的是 GNU Make,那么您可以在编译的预处理阶段简单地将 -D BASE_FILE_NAME=\"$*.c\" 传入(如果您单独执行它们,或者如果在单个阶段进行编译则,这是常态)。

这取决于您确定文件名的方式。我的来自一个普通文件名列表,并在稍后阶段使用 makefile 中的函数以目录为前缀。

IE,这对我来说效果很好,但你的里程可能会有所不同! :-)

我的制作“代码”的简化版本:

CLASSES = main.c init.c

PREPROCESSED = $(patsubst %.c,$(PPCDIR)/%.pp.c,$(CLASSES))

$(PREPROCESSED): $(PPCDIR)/%.pp.c: %.c $(ALLH) 
    $(GCC) $(GCCOPTS) -D BASE_FILE_NAME=\"$*\" -E $< > $@

在您的代码中随意使用 BASE_FILE_NAME :-)

【讨论】:

  • 不幸的是,我正在使用 CodeLite,它会为我生成 makefile。使用 CodeLite 非常棒,除非您想做一些不合常理的事情。还是不错的想法,+1
  • 同样的想法可以用在 Visual Studio 中。在 Visual Studio 2008 中:右键单击项目文件 (.vcproj) -> 属性 -> 配置属性 -> C/C++ -> 预处理器 -> 预处理器定义。添加 BASE_FILE__=\"$(InputFileName)\"。您可以在源文件中使用 __BASE_FILE 而不是 FILE
【解决方案2】:

没有提供该功能的已知预处理器宏。通过函数接缝传递__FILE__ 就像唯一明智的选择一样。

【讨论】:

  • 对于 gcc 有 __BASE_FILE__.
  • @fret :对我来说,__BASE_FILE__ 输出与__FILE__ 相同。如果您阅读链接到的文档,它会使用 main 函数(甚至不是当前文件)提供文件的名称(不一定是基本名称)。
  • 如果你可以使用 c++ 那么有一个 constexpr 解决方案:stackoverflow.com/a/38237385/52074
  • @TrevorBoydSmith 好点。但是,老实说,如果你看日期,这个问题是在 C++11 发布一个月后提出的,还没有被广泛采用。
【解决方案3】:

回复上面的 FredCooke,你可以换这个行:

-D BASE_FILE_NAME=\"$*.c\"

与:

-D BASE_FILE_NAME=\"$(<F)\"

这将为您提供正确的文件名扩展,对于 .cpp 也是如此。

【讨论】:

    【解决方案4】:

    正如在其他答案中已经提到的,唯一可移植的方法是从编译器传入一个定义,但是有编译器特定的扩展:

    • 叮当声:__FILE_NAME__
    • GCC:__BASE_FILE__

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-03-18
      • 2012-07-30
      • 1970-01-01
      • 2011-06-15
      • 2013-10-11
      • 2017-10-06
      • 2018-04-25
      • 1970-01-01
      相关资源
      最近更新 更多