【问题标题】:Expand C/C++ function macros without preprocessor无需预处理器即可展开 C/C++ 函数宏
【发布时间】:2015-03-08 22:12:17
【问题描述】:

如何在 C/C++ 文件中测试/扩展所有函数宏,而不通过预处理器运行它? 例如,是否有可以改变这种情况的程序或方法:

#include <iostream>
#define AAA(a) cout << "function "  << a << endl
using namespace std;
int main(){
AAA(12);
}

喜欢这个吗?

#include <iostream>
using namespace std;
int main(){
cout << "function " << 12 << endl;
}

我不想通过预处理器运行,因为文件中的所有包含使“gcc -E ”输出非常难看,我只想要几个简单的宏扩展而没有所有开销。

【问题讨论】:

  • 您可能会编写一些使用 clang 作为库的代码,并使用它的预处理器。除非grep -v ^\#include myfile|gcc -E 对你来说足够好。
  • Resharper for C++ 让您可以做到这一点。
  • 感谢 Mats 的建议,我会研究 Clang。但是,它将迭代超过 33k+ 行代码,所以我认为 grep 会变得有点脏。我现在在 Mac 上,但我会跳上 VM 并给 Resharper 一个机会。
  • @Involution:在#include 前面加上// {unique tag} 会更容易,通过普通的预处理器运行,然后再次删除// {unique tag}
  • @Involution:GCC 使用 -C 选项保留 cmets。

标签: c++ c-preprocessor


【解决方案1】:

不,这是不可能的。例如,您包含的标题可能包含您想要在正文中扩展的宏。还是您的意思是不扩展来自标头的任何宏?在这种情况下,预处理器绝对无法区分您想要什么和不想要什么。

如果您事先知道情况并非如此,那么我建议您只需编写一个脚本来删除包含,然后通过预处理器运行它。

【讨论】:

    【解决方案2】:

    我听到了关于该主题的所有可能的否定答案:

    • 宏只能扩展不能评估
    • 处理器还应该解析包含文件
    • 嵌套宏可能过于复杂
    • 条件预处理可能很棘手
    • 宏是邪恶的,只是避免它们
    • 等 等等……

    它们都是真实的,但 IMO 它们与日常编程的现实相冲突。

    事实上,在旧的 C 项目中工作,其中宏主要用作函数,这对我来说变得至关重要。使用 /P 生成所有预处理文件是可行的,但过于繁琐且耗时。我只需要一个工具来扩展一个简单的宏,该宏定义在其他文件的上方或最多几行。

    怎么做?

    1 Onl,inux 只需使用 GDB 和他的扩展宏功能 2 在 Windows 上,我使用 https://www.jetbrains.com/resharper-cpp/ 集成到 Visual Studio

    所以,是的,在实际意义上,这是可能的。

    【讨论】:

      【解决方案3】:

      保护#includes 不被扩展,以文本方式运行预处理器,删除文本预处理器生成的# 1 "&lt;stdint&gt;" 等垃圾并重新公开受保护的#includes。

      这个shell命令可以做到:

      sed 's|^\([ \t]*#[ \t]*include\)|magic_fjdsa9f8j932j9\1|' | cpp | \
           sed 's|^magic_fjdsa9f8j932j9||; /^# [0-9]/d'
      

      只要你把包含词放在一起,而不是像

      那样做疯狂的事
      #i\
      ncl\
      u??/
      de <iostream>
      

      (您可以在上面看到 2 个反斜杠续行 + 1 个三元组(??/ == \ )反斜杠续行)。

      如果你愿意,你可以用同样的方式保护#ifs #ifdefs #ifndefs #endifs 和#elses。

      【讨论】:

        【解决方案4】:

        假设您想查看 file.c。如果它包含函数 main,则需要更改该函数的名称才能使其正常工作。以下将文件打印到标准输出,仅添加了适度的丑陋。

        #include "file.c"
        #include <stdio.h>
        
        #define X(...) #__VA_ARGS__
        
        void print_file( char* s )
        {
           // a loop here to move through s until some identifier is found
           // in the original file, say a comment that says: //___START___HERE___
           while(*s){
              if( *s=='{' | *s=='}' | *s=='#' ) printf("\n");
              printf("%c",*s);
              if( *s==';' ) printf("\n");
              }
        }
        
        int main(int argc, char* argv[])
        {
            print_file(X(
            #include "file.c"
            ));
            return 0;
        }
        

        【讨论】:

        • 这将打印文件中的所有包含。
        • @Puppy,这是一个非常小的问题。直到您发现名称 main 更改为或某些设置的注释或其他内容时,您才可以打印。这就像两行额外的代码。
        • 我不是说要解析它,只是在要开始打印的原始文件中添加注释。递增 s 直到 !strcmp(s,c),其中 c 是注释。预处理都是通过包含原始文件完成的,因此也包含了它的所有宏。
        • 您假设包含中没有代码恰好与新名称/特殊注释匹配。
        • 这应该很容易做到。如果您真的担心,请使用 md5sum。你更有可能在完成之前被流星击中,以这种方式发生冲突。它不像 OP 需要将其部署为某种商业解决方案,它只需要在使用时工作。如果没有,则可以对其进行调整。
        猜你喜欢
        • 2012-09-20
        • 2018-01-04
        • 1970-01-01
        • 1970-01-01
        • 2014-11-27
        • 2020-10-18
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多