不使用预处理器展开C/C++函数宏

7

我该如何在不通过预处理器的情况下测试/扩展C/C++文件中的所有函数宏?例如,是否有一种程序或方法可以更改以下内容:

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

将此转换为HTML代码?
#include <iostream>
using namespace std;
int main(){
cout << "function " << 12 << endl;
}

我不想运行预处理器,因为文件中的所有包含使得“gcc -E <>”输出非常丑陋,我只想要一些简单的宏展开而没有所有的开销。


4
你可以编写一些代码来使用clang作为库,并使用它的预处理器。除非grep -v ^\#include myfile|gcc -E 已经足够好用了。 - Mats Petersson
Resharper for C++ 可以让你做到这一点。 - chris
4
只需在 #include 前加上 // {unique tag},然后通过普通的预处理器运行它,最后再删除 // {unique tag} 就可以了。 - MSalters
思想上,@MSalters 的解决方案可行。但是,当被注释掉时,预处理器会完全删除 #include 标签和其依赖项。与上面相同的问题,当被注释掉时,包含语句也会消失。真正的难题。 - Involution
4
GCC在使用-C选项时会保留注释。 - MSalters
显示剩余4条评论
4个回答

2
不可能。你的包含头文件中可能包含宏,需要在代码主体中展开。或者你是指不展开来自头文件的任何宏?在这种情况下,预处理器完全无法区分你想要什么和你不想要什么。
如果你事先知道这不是问题,我建议你编写一个脚本来删除头文件,然后再运行预处理器。

2
我听到了所有可能的关于这个主题的负面回答:
  • 宏只能被扩展而不能被评估
  • 处理器应该解析包括文件
  • 嵌套宏可能过于复杂
  • 条件预处理可能会棘手
  • 宏是邪恶的,只需避免使用它们
  • 等等...
它们都是正确的,但在我看来,它们与日常编程的现实相冲突。
事实上,在旧的C项目上工作时,宏通常被简单地用作函数,这对我来说变得至关重要。使用 /P 生成所有预处理文件虽然可行,但是过于繁琐且耗时。我只需要一个工具,可以扩展在几行代码或最多其他文件中定义的简单宏。
如何做?
1. 在Linux上,只需使用GDB及其扩展宏功能即可。 2. 在Windows上,我使用集成到Visual Studio中的https://www.jetbrains.com/resharper-cpp/
因此,在实际意义上,这是可能的。

0

保护#include不被扩展,按文本方式运行预处理器,删除文本预处理器生成的# 1 "<stdint>"等垃圾,并重新公开受保护的#include

这个Shell命令可以实现:

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

只要您将include单词保持在一起,而不是像疯子一样胡乱搞,就可以了。
#i\
ncl\
u??/
de <iostream>

(你可以看到上面有2个反斜杠继续行符号 + 1个三字符组(??/ == \ )反斜杠继续行符号)。

如果你愿意,你也可以以同样的方式保护 #if#ifdef#ifndef#endif#else


-1
假设您想查看 file.c 文件。如果它包含主要函数,则需要更改该函数的名称才能使其正常工作。以下代码将文件打印到标准输出,但增加了适度的丑陋程度。
#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
@Puppy,那只是一个非常小的问题。你只需要在找到名称main更改为某个设置注释或其他内容之前不打印即可。这只需要额外两行代码。 - Kyle
我并不是要求解析它,只需在原始文件中想要开始打印的位置添加注释。将s递增直到!strcmp(s,c),其中c是注释。预处理是通过包含原始文件完成的,因此包含了所有宏。 - Kyle
您假设包含文件中的代码与新名称/特殊注释不匹配。 - Puppy
这应该很容易做到。如果你真的担心,可以使用md5sum。以那种方式发生冲突的可能性比完成它被流星击中的可能性更大。这不像OP需要将其部署为某种商业解决方案,它只需要在使用时正常工作即可。如果不行,可以进行微调。 - Kyle
显然,拥有一个干净的解决方案是很好的。但是一个不太完美的解决方案总比“无法工作”要好。 - Kyle

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接