C++ 计算C+中的所有宏+;头文件
我有一个要求,建立一个自动化系统来分析一个C++ .h文件,其中有很多<代码> >定义< /Cord>语句,并用每个<代码>定义< <代码>的值来完成。除了C++ 计算C+中的所有宏+;头文件,c++,macros,c-preprocessor,constants,compile-time-constant,C++,Macros,C Preprocessor,Constants,Compile Time Constant,我有一个要求,建立一个自动化系统来分析一个C++ .h文件,其中有很多 >定义< /Cord>语句,并用每个定义< 的值来完成。除了#define语句外,.h文件中还有许多其他垃圾 目标是创建一个键值列表,其中键值是由#define语句定义的所有关键字,值是对与定义相对应的宏的求值。#defines使用一系列嵌套宏定义关键字,这些宏最终解析为编译时整数常量。有些无法解析为编译时整数常量,必须跳过这些 h文件将随着时间的推移而演变,因此该工具不能是一个长的硬编码程序,它实例化一个等于每个关键字的变
#define
语句外,.h文件中还有许多其他垃圾
目标是创建一个键值列表,其中键值是由#define
语句定义的所有关键字,值是对与定义相对应的宏的求值。#defines
使用一系列嵌套宏定义关键字,这些宏最终解析为编译时整数常量。有些无法解析为编译时整数常量,必须跳过这些
h文件将随着时间的推移而演变,因此该工具不能是一个长的硬编码程序,它实例化一个等于每个关键字的变量。我无法控制.h文件的内容。唯一的保证是它可以用标准的C++编译器构建,并且更多的代码< >代码>将被添加但不会被删除。宏公式可能随时更改
我看到的解决方案有:
#ifndef Constants_h
#define Constants_h
namespace Foo
{
#define MAKE_CONSTANT(A, B) (A | (B << 4))
#define MAGIC_NUMBER_BASE 40
#define MAGIC_NUMBER MAGIC_NUMBER_BASE + 0x2
#define MORE_MAGIC_1 345
#define MORE_MAGIC_2 65
// Other stuff...
#define CONSTANT_1 MAKE_CONSTANT (MAGIC_NUMBER + 564, MORE_MAGIC_1 | MORE_MAGIC_2)
#define CONSTANT_2 MAKE_CONSTANT (MAGIC_NUMBER - 84, MORE_MAGIC_1 & MORE_MAGIC_2 ^ 0xA)
// etc...
#define SKIP_CONSTANT "What?"
// More CONSTANT_N mixed with more other stuff and constants which do
// not resolve to compile-time integers and must be skipped
}
#endif Constants_h
这个输出采用什么格式并不重要,只要我能将它作为一个键值对列表进一步使用。以下是一个概念,基于澄清评论中的假设
- 只有一个标题
- 不包括
- 不依赖于包含代码的文件
- 不依赖以前包含的标题
- 不依赖于包含顺序
- 不要冒险影响二进制构建过程 (构成实际软件产品的部分)
- 不要试图模拟二进制构建编译器/解析器
- 复印
- 从专用代码文件中包含它,
仅包含“#包括“copy.h”;
或者直接对表头进行预处理
(这与我的习惯格格不入) - 删除除预处理器和pragmas之外的所有内容, 注意线路延续
- 将所有“#define”替换为“HaPoDefine”, 除了一个(例如第一个)
- 重复
- 对包含的代码文件进行预处理 (大多数编译器都有一个开关来执行此操作)
- 保存输出
- 将另一个“HaPoDefine”变回“#define”
- 直到没有“HaPoDefine”留下
- 从中间存储的增量中获取所有宏展开
- 抛弃一切不相关的东西
- 因为最终的实际数值很可能是编译器(而不是预处理器)的结果,所以使用bashs“expr”之类的工具来计算人眼可读性的值,
小心不要让差异影响二进制构建过程 - 使用一些正则表达式魔术来实现任何想要的格式
- 一种方法是编写一个“程序生成器”,生成一个程序(printDefines程序),该程序由
std::cout等语句组成。您可以使用g++
或gcc
和-E选项,并处理该输出吗
-E在预处理阶段后停止;不要正确运行编译器。
输出是预处理源代码的形式,它
发送到标准输出。不需要
预处理被忽略
有了这个,我想:
从源代码创建所有#define
键的列表
对源文件运行下面适当的命令,让GNU预处理器完成它的工作
从stdout中获取预处理的结果,过滤以仅获取整数形式的结果,并将其输出到您想要表示键/值对的位置
以下两个命令之一:
gcc -E myFile.c
g++ -E myFile.cpp
只需使用现有的C预处理器就可以了。常规的GNUcpp
和-dU
选项应该可以让你非常接近你想要的结果。为什么输出中常量_1
和常量_2
,但是魔数基数
,魔数
,更多魔数
,RE_MAGIC_2
不是吗?它们似乎符合您的标准(定义编译时整数常量的解析)至少和其他两个一样好。@BenVoigt它们应该在输出中,我现在就解决它。@MatteoItalia我在cpp上使用-dU标志时没有得到任何预期的输出值。我需要另一个标志吗?@Techrocket9:问题是预处理器的规则根本不能满足您的要求。当外部宏被使用,而不是在它被定义的地方。因此,CONSTANT_1
在被使用之前不是编译时整数表达式……而且可能有些用法是,有些用法不是。澄清一下:至少现在,我必须解析的是单个头文件,所以我不需要担心includes。使用了.h文件并修改了它ied由许多使用多个编译器的团队(我知道GCC和MSVC)编写,应该仍然是C++/14。该文件只需要符合二进制bu
# printDefines.sh
g++ -std=c++11 -dM -E someHeaderfile.h > defines.txt
./generateDefinesCpp someHeaderfile.h defines.txt > defines.cpp
g++ -std=c++11 -o defines.o defines.cpp
./defines.o
#include <stdio.h>
#include <string>
#include <iostream>
#include <fstream>
#include <cstring>
using std::cout;
using std::endl;
/*
* Argument 1: name of the headerfile to scan
* Argument 2: name of the cpp-file to generate
* Note: will crash if parameters are not provided.
*/
int main(int argc, char* argv[])
{
cout << "#include<iostream>" << endl;
cout << "#include<stdio.h>" << endl;
cout << "#include \"" << argv[1] << "\"" << endl;
cout << "int main() {" << endl;
std::ifstream headerFile(argv[2], std::ios::in);
std::string buffer;
char macroName[1000];
int macroValuePos;
while (getline(headerFile,buffer)) {
const char *bufferCStr = buffer.c_str();
if (sscanf(bufferCStr, "#define %s %n", macroName, ¯oValuePos) == 1) {
const char* macroValue = bufferCStr+macroValuePos;
if (macroName[0] != '_' && strchr(macroName, '(') == NULL && *macroValue) {
cout << "std::cout << \"" << macroName << "\" << \" \" << (" << macroValue << ") << std::endl;" << std::endl;
}
}
}
cout << "return 0; }" << endl;
return 0;
}
#define CONSTANT_1 MAKE_CONSTANT (MAGIC_NUMBER + 564, MORE_MAGIC_1 | MORE_MAGIC_2)
#define CONSTANT_2 MAKE_CONSTANT (MAGIC_NUMBER - 84, MORE_MAGIC_1 & MORE_MAGIC_2 ^ 0xA)
#define Constants_h
#define MAGIC_NUMBER MAGIC_NUMBER_BASE + 0x2
#define MAGIC_NUMBER_BASE 40
#define MAKE_CONSTANT(A,B) (A | (B << 4))
#define MORE_MAGIC_1 345
#define MORE_MAGIC_2 65
#define OBJC_NEW_PROPERTIES 1
#define SKIP_CONSTANT "What?"
#define _LP64 1
#define __APPLE_CC__ 6000
#define __APPLE__ 1
#define __ATOMIC_ACQUIRE 2
#define __ATOMIC_ACQ_REL 4
...
#include<iostream>
#include<stdio.h>
#include "someHeaderfile.h"
int main() {
std::cout << "CONSTANT_1" << " " << (MAKE_CONSTANT (MAGIC_NUMBER + 564, MORE_MAGIC_1 | MORE_MAGIC_2)) << std::endl;
std::cout << "CONSTANT_2" << " " << (MAKE_CONSTANT (MAGIC_NUMBER - 84, MORE_MAGIC_1 & MORE_MAGIC_2 ^ 0xA)) << std::endl;
std::cout << "MAGIC_NUMBER" << " " << (MAGIC_NUMBER_BASE + 0x2) << std::endl;
std::cout << "MAGIC_NUMBER_BASE" << " " << (40) << std::endl;
std::cout << "MORE_MAGIC_1" << " " << (345) << std::endl;
std::cout << "MORE_MAGIC_2" << " " << (65) << std::endl;
std::cout << "OBJC_NEW_PROPERTIES" << " " << (1) << std::endl;
std::cout << "SKIP_CONSTANT" << " " << ("What?") << std::endl;
return 0; }
CONSTANT_1 1887
CONSTANT_2 -9
MAGIC_NUMBER 42
MAGIC_NUMBER_BASE 40
MORE_MAGIC_1 345
MORE_MAGIC_2 65
OBJC_NEW_PROPERTIES 1
SKIP_CONSTANT What?
gcc -E myFile.c
g++ -E myFile.cpp