GCC - 打印结构的定义
Posted
技术标签:
【中文标题】GCC - 打印结构的定义【英文标题】:GCC - Print the definition of a struct 【发布时间】:2016-10-15 10:56:12 【问题描述】:C 程序是否可以打印结构的定义?拥有成员名称会很棒,但只需一个有序的数据类型列表(以及数组的数组长度)就足够了。
我一直在寻找预处理器指令来实现这一点,但找不到任何东西。是否有预处理器指令可以获取代码的注释部分并将其用作#define 变量。如果是这样,我可以初始化一些 sting 变量来保存 #define 变量的值。
例如,像这样的结构按原样打印
struct foo
int a;
char b;
short arr[6];
或者这样
struct s
int m1;
char m2;
short m3[6];
只要可以从数据中重新创建结构,格式并不重要。所以这样的事情也可以:
sint,char,short[10]
仅供参考,这是一个资源受限的基于 ARM 的设备。
我不想手动将结构代码复制粘贴到打印语句中。如果struct代码改变了,而print语句没有改变,就会产生错误的结果。
【问题讨论】:
据我所知,不在标准 C 中。绝对不是通过 C 预处理器(通过“#define 变量”,你的意思是一个 C 预处理器宏),因为它不知道 C 本身是如何工作的。 @Rhymoid 不同意这一点;您可以使用预处理器为#define structname_code ...
复制相关代码并对其进行实例化。
“我不想手动复制粘贴结构代码”——可以让程序读取自己的源代码文件。
第二个@MarcusMüller。您可以创建封装类型和成员定义的定义,并将名称放入稍后评估的数据结构中。
谢谢@MarcusMüller 这应该是一个答案
【参考方案1】:
有些目标文件格式包含您需要的信息,并允许以编程方式访问。其中之一是Dwarf。调试器通常使用此信息。
我不认为(但我不确定)可以访问运行代码的调试信息。这与在复杂的运行时系统(如 Java 或 .net 系列)中运行的语言程序不同。那些可以对自己使用反射。
在用传统编译语言编写的程序中,您可能会打开一个目标文件——可能是正在运行的可执行文件本身! -- 并以编程方式检查它,就像调试器一样。考虑到这一点,可以想象分析源代码会更容易(在 C 和 C++ 中,源代码必须可用于头文件形式的许多类型定义)。但是对于非平凡的用途,这种想法可能具有欺骗性,因为编译器已经为您分析和解析了源代码,并将所有信息放在可以轻松访问的整洁数据结构中。如果您对源进行操作,则编译过程的这一部分(即前端的相当一部分)必须由您完成。
【讨论】:
【参考方案2】:如果您已经拥有源代码,为什么还要这样做?
但一般来说,C 编译器不提供选项,例如“列出”它在编译期间看到的所有结构。编译器将保留内部符号表,但没有人想到需要能够打印这些符号表。在编译期间读取的所有源文件和头文件中也可能有数百个结构和类型。
还要注意,类型、字段和变量的名称主要是为了给程序员赋予意义。编译后,很多名字都会消失。只有全局变量和缺少的外部变量会在目标文件中保留它们的名称,以便能够在链接期间解决这些问题,并且在链接之后,不再需要这些名称。例如,编译器已将a->b
转换为b
相对于内存中a
所在位置的偏移量。
【讨论】:
"如果您已经拥有源代码,为什么还要这样做?"我有嵌入式物联网设备。现场可能有很多这样的设备。该设备将发送二进制 blob。这些设备可能运行不同的固件版本,并且 blob 结构可能因固件版本而异。传统的方法是传达固件版本并让服务器知道每个版本的 blob 结构。更复杂的是,设备内存可能包含以前固件版本存储的数据。我想让数据自我描述。 有些解决方法不涉及了解结构。但是它们很混乱并且施加了限制。我喜欢 JSON / bJSON 的想法。唯一的缺点是数据开销,一旦你付出了这个代价,它就会形成一个非常敏捷的信息系统,所有节点不必在同一个版本上就可以成功通信。 问题本身提到了我不会将结构粘贴到 sprintf 中的原因。也许作为最后的手段,我会这样做,但我正在努力寻找更好的方法来做到这一点。一位用户实际上在评论中留下了一个非常有用的 hack。 -1,因为 GCC 有 -save-temps,它会创建一个 .self-contained 文件,其中包括“它在编译期间看到的所有结构”等。以上是关于GCC - 打印结构的定义的主要内容,如果未能解决你的问题,请参考以下文章
gcc - 如何在结构定义中结合 __attribute__((dllexport)) 和 [[nodiscard]]?
C++ 构造函数中体系结构 x86_64 的 GCC 未定义符号