本文致力于介绍 gcc 或 clang 等主要编译器作为 C 应用程序反射信息源的能力,这使得像 Metac 这样的 C 反射实现成为可能。这适用于相应平台 Linux、macOS 和 Windows 上的 elf、macho 和 pe 格式。
传统上,C 并不像其他一些编程语言那样支持反射功能。这是因为 C 优先考虑效率和控制。然而,缺乏反思并不一定意味着缺乏自省能力。例如,调试器严重依赖嵌入在可执行文件中的调试信息。这些信息甚至超出了反射所需的范围,包括代码中定义的类型、行号、源代码引用、符号信息,甚至变量和函数参数在堆栈上的位置等详细信息。最常见的调试信息格式之一称为 DWARF,它是 ELF 格式的原生格式,用于公开调试器所需的所有数据。更好的是,这种格式也适用于 Mach-O(MacOs 可执行格式)和 PE(Windows 可执行格式)。
这就引出了一个问题:应用程序不能直接利用这些数据来获得自我意识吗?这就是为什么它不像看起来那么简单:
这意味着需要一个专门的工具来有效地读取、过滤 DWARF 数据(或其他格式的等效数据)并将其转换为应用程序可用的格式。输入Metac。
Metac 利用可执行格式中现有的 DWARF(或等效)信息来为 C 代码提供有针对性的反射形式。这允许应用程序访问数据的相关子集,促进内省,而没有完整调试信息的缺点。 Metac 弥补了这一差距,并允许 C 程序在运行时查询该数据,使它们能够提取有关自己的类型、变量和函数的信息。这种新发现的自我意识使 C 程序能够更有效地调试、动态行为和潜在的未来功能。
虽然 DWARF 数据可用于其他平台上的目标文件,但 macOS 存在一些障碍。在 macOS 上,默认情况下通常不会生成 DWARF 信息,并且需要 dsymutil 工具仅为链接的可执行二进制文件显式创建它。
为了确保跨平台行为一致,Metac 采用了两步方法,该方法将在 macOS 上运行并与其他平台兼容:
这个多步骤过程可能看起来很复杂,但它在 Makefile 中实现了自动化,从而简化了开发人员的工作流程。重要的是要记住,Metac 正在从完整构建和链接的应用程序中获取 DWARF,即使此过程可以针对其他平台进行更改。
让我们深入研究一个实际示例。 想象一个管理复杂数据结构(如链表)的 C 程序。传统上,调试结构内的任何问题都需要手动代码检查。然而,使用 Metac,程序可以内省自己的链表,检查指针和值等元素。这允许在运行时对列表进行有针对性的调试和操作。
这是一个简化的代码示例,演示了如何使用 Metac 来检查 struct test 类型的变量:
//main.c #include <stdio.h> // printf #include <stdlib.h> // 自由 #include <math.h> // M_PI,M_E #include“metac/reflect.h” 结构测试{ 整数y; 字符c; 双圆周率; 双 e; 短_未初始化_字段; }; int main(){ // 我们需要使用这个结构来包装变量声明 // 获取其类型信息 WITH_METAC_DECLLOC(decl_location, 结构测试 t = { .y = -10, .c = 'a', .pi = M_PI, .e = M_E, }; ) metac_value_t *p_val = METAC_VALUE_FROM_DECLLOC(decl_location, t); 字符 * s; s =metac_entry_cdecl(metac_value_entry(p_val)); // 接下来将输出“struct test t =” printf("%s = ", s); 免费; s =metac_value_string(p_val); // 接下来将输出“{.y = -10, .c = 'a', .pi = 3.141593, .e = 2.718282, ._uninitialized_field = 0,};n” printf("%s;n", s); 免费; metac_value_delete(p_val); 返回0; } </math.h></stdlib.h></stdio.h>
解释:
此示例演示了如何使用 Metac:
这只是一个基本示例,但它展示了 Metac 用于 C 代码自省的强大功能。
为了构建它,需要在构建过程发生的主机上安装 Metac。
这是用于构建示例的类似 KBUILD 的 Makefile:
ifeq ($(M),) METAC_ROOT=../.. 全部:测试目标 目标: $(MAKE) -C $(METAC_ROOT) M=$(PWD) 目标 干净的: $(MAKE) -C $(METAC_ROOT) M=$(PWD) 干净 测试: $(MAKE) -C $(METAC_ROOT) M=$(PWD) 测试 .PHONY:全部干净测试 万一 规则+= 目标 _meta_c_app c_app.reflect.c c_应用程序 LDFLAGS-c_app=-Lsrc -lmetac LDFLAGS-_meta_c_app=-Lsrc -lmetac in_c_app+=main.o TPL-_meta_c_app:=bin_target IN-_meta_c_app=$(in_c_app:.o=.meta.o) POST-_meta_c_app=$(METAC_POST_META) TPL-c_app:=bin_target IN-c_app=$(in_c_app) c_app.reflect.o DEPS-c_app=src/libmetac.a TPL-c_app.reflect.c:=metac_target METACFLAGS-c_app.reflect.c+=运行metac-reflect-gen $(METAC_OVERRIDE_IN_TYPE) IN-c_app.reflect.c=_meta_c_app TPL-目标:=phony_target IN-目标:=c_app
解释:
规则目标:
TPL-target:=phony_target IN-目标:=c_app
生成为.PHONY,需要使用相应的规则构建最终目标c_app。
规则c_app:
TPL-c_app:=bin_target IN-c_app=$(in_c_app) c_app.reflect.o DEPS-c_app=src/libmetac.a
是从 main.o 和 c_app.reflect.o 以及 libmetac.a 构建可执行二进制文件的规则。 Make 知道如何从 main.c 自动构建 main.o。我们从哪里获取 c_app.reflect.o ?来自 c_app.reflect.c:
规则 c_app.reflect.c:
TPL-c_app.reflect.c:=metac_target METACFLAGS-c_app.reflect.c+=运行metac-reflect-gen $(METAC_OVERRIDE_IN_TYPE) IN-c_app.reflect.c=_meta_c_app
是一个使用metac工具的规则,其参数运行metac-reflect-gen $(METAC_OVERRIDE_IN_TYPE)。输入文件是_meta_c_app。该组合将指示metac从_meta_c_app读取DWARF数据。参数 METAC_OVERRIDE_IN_TYPE 用于指定metac 是否必须期望 elf、macho 或 pe 作为输入。 metac-reflect-gen 是一个 go-template 模块名称,它生成 c_app.reflect.c.
规则_meta_c_app:
TPL-_meta_c_app:=bin_target IN-_meta_c_app=$(in_c_app:.o=.meta.o) POST-_meta_c_app=$(METAC_POST_META)
与c_app类似,但它使用main.meta.o作为源。 main.meta.o 和 main.o 之间的唯一区别是第一个是使用标志 -g3 -D_METAC_OFF_ 构建的。
如果我们在 macOS 上运行 make 我们应该看到:
% 制作 /Library/Developer/CommandLineTools/usr/bin/make -C ../.. M=/Users/user/Workspace/metac/examples/c_app_simplest 测试 /Library/Developer/CommandLineTools/usr/bin/make -C ../.. M=/Users/user/Workspace/metac/examples/c_app_simplest 目标 cc -I./include -c -MMD -MF /Users/user/Workspace/metac/examples/c_app_simplest/main.d -MP -MT '/Users/user/Workspace/metac/examples/c_app_simplest/main.o /用户/用户/工作空间/metac/examples/c_app_simplest/main.d' -o /Users/user/Workspace/metac/examples/c_app_simplest/main.o /Users/user/Workspace/metac/examples/c_app_simplest/main.c cc -I./include -g3 -D_METAC_OFF_ -c -MMD -MF /Users/user/Workspace/metac/examples/c_app_simplest/main.meta.d -MP -MT '/Users/user/Workspace/metac/examples/ c_app_simplest/main.meta.o /Users/user/Workspace/metac/examples/c_app_simplest/main.meta.d' -o /Users/user/Workspace/metac/examples/c_app_simplest/main.meta.o /Users/user /工作区/metac/examples/c_app_simplest/main.c cc /Users/user/Workspace/metac/examples/c_app_simplest/main.meta.o -Lsrc -lmetac -o /Users/user/Workspace/metac/examples/c_app_simplest/_meta_c_app (其中 dsymutil) && dsymutil /Users/user/Workspace/metac/examples/c_app_simplest/_meta_c_app || echo“找不到 dsymutil” /usr/bin/dsymutil ./metac run metac-reflect-gen -s 'path_type: "macho"' -s 'path: "/Users/user/Workspace/metac/examples/c_app_simplest/_meta_c_app"' > /Users/user/Workspace/metac/示例/c_app_simplest/c_app.reflect.c cc -I./include -c -MMD -MF /Users/user/Workspace/metac/examples/c_app_simplest/c_app.reflect.d -MP -MT '/Users/user/Workspace/metac/examples/c_app_simplest/c_app. Reflect.o /Users/user/Workspace/metac/examples/c_app_simplest/c_app.reflect.d' -o /Users/user/Workspace/metac/examples/c_app_simplest/c_app.reflect.o /Users/user/Workspace/metac /examples/c_app_simplest/c_app.reflect.c cc /Users/user/Workspace/metac/examples/c_app_simplest/main.o /Users/user/Workspace/metac/examples/c_app_simplest/c_app.reflect.o -Lsrc -lmetac -o /Users/user/Workspace/metac/示例/c_app_simplest/c_app
现在,如果我们运行该应用程序,我们将看到:
% ./c_app 结构测试 t = {.y = -10, .c = 'a', .pi = 3.141593, .e = 2.718282, ._uninitialized_field = 0,};
示例可以在这里找到。
有关如何使用metac的更多信息可以在这里找到
结论:
Metac 不仅仅是一个工具;更是一个工具。这是 C 代码自我改进的途径。借助 DWARF 的洞察力和 Metac 的解释,您的程序可以揭示他们的“无意识”行为并释放他们的全部潜力。
以上就是C 反思:当善良的老矮人让你的精灵面对他们无意识的真相时的详细内容,更多请关注其它相关文章!
掌握技巧,轻松查看远程端口号以下是按照您的要求编写的解释性内容:为了高效地管理和维护网络,了解如何查看远程设备的端口号至关重要。通过掌握正确的方法和工具,您可以轻松地查看远程端口号,确保网络通信的安全和顺畅。这不仅有助于识别潜在的安全风险,还能提高网络性能和可靠性。
C 反思:当善良的老矮人让你的精灵面对他们无意识的真相时-C++
文件复制失败:原因揭秘,快速解决之道
月租服务器,超值特惠,低至XX元起!
golang 框架中提高开发效率的新特性是什么?-Golang
Natapp远程端口设置,精准填写指南
CAD粘贴板复制失效?高手教你解决之道!
golang 框架中提高开发效率的新特性是什么?-Golang
数学中的绝对值被定义为 x 非负值,不考虑其符号。绝对值表示变量
[WIP] JavaScript Vs Golang: Complexity-Golang
冲啊,原始人怎么升金星? 原始英雄升星材料获取策略-手机游戏策略
如何匹配绝区零乱队-手游攻略
《原神》富有幻想配方大全-手机游戏策略
《绝区零》狼叔主副词条对应效果详解-手机游戏策略
燕云十六侠迹开封卷一文伞任务怎么办?手机游戏策略
《创世战车》独特部件功能介绍-手机游戏策略
TopOn&Taku 2024年出现了最新的广告实现策略 ChinaJoy,邀请您探索实现优化的方法——游戏新闻
“绝区零”寻找温暖的家庭任务策略-手机游戏策略
“绝区零”丽娜培训建议-手游策略