news 2026/7/2 5:22:03

不过这么看 Hello World! 还是太长了,不适合用来一上来就展示,我们换个简单点的输出 123:

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
不过这么看 Hello World! 还是太长了,不适合用来一上来就展示,我们换个简单点的输出 123:

那我们上 godbolt 看看 .NET 给我们的 Brainfuck 程序产生了怎样的机器代码?

Copy

push rbp push r15 push r14 push r13 push rbx lea rbp, [rsp+0x20] mov rbx, rsi mov r15, r8 movsxd rsi, edi add rsi, rbx add byte ptr [rsi], 49 ; '1' inc edi movsxd rsi, edi add rsi, rbx add byte ptr [rsi], 50 ; '2' inc edi movsxd rsi, edi add rsi, rbx add byte ptr [rsi], 51 ; '3' lea r14d, [rdi-0x02] movsxd rsi, r14d movzx rsi, byte ptr [rbx+rsi] mov rdi, r15 mov rax, qword ptr [r15] mov r13, qword ptr [rax+0x68] call [r13]System.IO.Stream:WriteByte(ubyte):this inc r14d movsxd rsi, r14d movzx rsi, byte ptr [rbx+rsi] mov rdi, r15 call [r13]System.IO.Stream:WriteByte(ubyte):this inc r14d movsxd rsi, r14d movzx rsi, byte ptr [rbx+rsi] mov rdi, r15 call [r13]System.IO.Stream:WriteByte(ubyte):this mov eax, r14d pop rbx pop r13 pop r14 pop r15 pop rbp ret

这不就是

Copy

*(ptr++) = '1'; *(ptr++) = '2'; *ptr = '3'; ptr -= 2; WriteByte(*(ptr++)); WriteByte(*(ptr++)); WriteByte(*ptr);

吗?可以看到我们代码里的抽象全都被 .NET 给优化干净了。

而前面那个不怎么直观的 Hello World! 代码则编译出:

Copy

AddData<8, Loop< AddPointer<1, AddData<4, Loop< AddPointer<1, AddData<2, AddPointer<1, AddData<3, AddPointer<1, AddData<3, AddPointer<1, AddData<1, AddPointer<-4, AddData<-1, Stop>>>>>>>>>>, AddPointer<1, AddData<1, AddPointer<1, AddData<1, AddPointer<1, AddData<-1, AddPointer<2, AddData<1, Loop<AddPointer<-1, Stop>, AddPointer<-1, AddData<-1, Stop>> >>>>>>>>> >>>, AddPointer<2, OutputData<AddPointer<1, AddData<-3, OutputData<AddData<7, OutputData<OutputData<AddData<3, OutputData<AddPointer<2, OutputData<AddPointer<-1, AddData<-1, OutputData<AddPointer<-1, OutputData<AddData<3, OutputData<AddData<-6, OutputData<AddData<-8, OutputData<AddPointer<2, AddData<1, OutputData<AddPointer<1, AddData<2, OutputData<Stop>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

JIT 编译#

如果我们想以 JIT 的形式运行 Brainfuck 代码,那如何在运行时生成类型然后运行代码呢?我们在 .NET 中有完善的反射支持,因此完全可以做到运行时创建类型。

比如根据数字来生成数字类型:

Copy

var type = GetNum(42); static Type GetHex(int hex) { return hex switch { 0 => typeof(Hex0), 1 => typeof(Hex1), 2 => typeof(Hex2), 3 => typeof(Hex3), 4 => typeof(Hex4), 5 => typeof(Hex5), 6 => typeof(Hex6), 7 => typeof(Hex7), 8 => typeof(Hex8), 9 => typeof(Hex9), 10 => typeof(HexA), 11 => typeof(HexB), 12 => typeof(HexC), 13 => typeof(HexD), 14 => typeof(HexE), 15 => typeof(HexF), _ => throw new ArgumentOutOfRangeException(nameof(hex)), }; } static Type GetNum(int num) { var hex0 = num & 0xF; var hex1 = (num >>> 4) & 0xF; var hex2 = (num >>> 8) & 0xF; var hex3 = (num >>> 12) & 0xF; var hex4 = (num >>> 16) & 0xF; var hex5 = (num >>> 20) & 0xF; var hex6 = (num >>> 24) & 0xF; var hex7 = (num >>> 28) & 0xF; return typeof(Int<,,,,,,,>).MakeGenericType(GetHex(hex7), GetHex(hex6), GetHex(hex5), GetHex(hex4), GetHex(hex3), GetHex(hex2), GetHex(hex1), GetHex(hex0)); }

同理也可以用于生成各种程序结构上。

最后我们只需要对构建好的类型进行反射然后调用Run方法即可:

Copy

var run = (EntryPoint)Delegate.CreateDelegate(typeof(EntryPoint), type.GetMethod("Run")!); run(0, memory, input, output); delegate int EntryPoint(int address, Span<byte> memory, Stream input, Stream output);

AOT 编译#

那如果我不想 JIT,而是想 AOT 编译出来一个可执行文件呢?

你会发现,因为编译出的东西是类型,因此我们不仅可以在 JIT 环境下跑,还能直接把类型当作程序 AOT 编译出可执行文件!只需要编写一个入口点方法调用Run即可:

Copy

using HelloWorld = AddData<8, Loop< AddPointer<1, AddData<4, Loop< AddPointer<1, AddData<2, AddPointer<1, AddData<3, AddPointer<1, AddData<3, AddPointer<1, AddData<1, AddPointer<-4, AddData<-1, Stop>>>>>>>>>>, AddPointer<1, AddData<1, AddPointer<1, AddData<1, AddPointer<1, AddData<-1, AddPointer<2, AddData<1, Loop<AddPointer<-1, Stop>, AddPointer<-1, AddData<-1, Stop>> >>>>>>>>> >>>, AddPointer<2, OutputData<AddPointer<1, AddData<-3, OutputData<AddData<7, OutputData<OutputData<AddData<3, OutputData<AddPointer<2, OutputData<AddPointer<-1, AddData<-1, OutputData<AddPointer<-1, OutputData<AddData<3, OutputData<AddData<-6, OutputData<AddData<-8, OutputData<AddPointer<2, AddData<1, OutputData<AddPointer<1, AddData<2, OutputData<Stop>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>; static void Main() { HelloWorld.Run(0, stackalloc byte[16], Console.OpenStandardInput(), Console.OpenStandardOutput()); }

然后调用 AOT 编译:

Copy

dotnet publish -c Release -r linux-x64 /p:PublishAot=true /p:IlcInstructionSet=native /p:OptimizationPreference=Speed

上面的/p:IlcInstructionSet=native即 C++ 世界里的-march=nativeOptimizationPreference=Speed则是-O2

运行编译后的程序就能直接输出Hello World!

性能测试#

这里我们采用一段用 Brainfuck 编写的 Mandelbrot 程序进行性能测试,代码见 Pastebin。

它运行之后会在屏幕上输出:

这段程序编译出来的类型也是非常的壮观:

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/2 5:20:13

Java毕业设计-基于 Java 的高中综合素质评价档案系统的设计与实现 基于 Java 的高中生社会实践档案管理系统(源码+LW+部署文档+全bao+远程调试+代码讲解等)

博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围&#xff1a;&am…

作者头像 李华
网站建设 2026/7/2 5:14:26

从软件工程的角度解读任正非的新年公开信

昨天被任正非的那封《全面提升软件工程能力与实践&#xff0c;打造可信的高质量产品》的公开信刷屏了&#xff0c;作为一个软件工程专业科班出身的软件开发从业者&#xff0c;自然是引起了我&#xff08;宝玉xp&#xff09;的好奇&#xff0c;仔细阅读之下确实让我大吃一惊&…

作者头像 李华
网站建设 2026/7/2 5:14:22

kokorotts安装与使用

kokorotts安装与使用安装python包下载模型简单使用安装python包 #安装 Kokoro 主包 pip install kokoro下载模型 #安装modelscope包。通过modelscope下载 pip install modelscope #下载模型, local_dir指定下载位置 modelscope download --model AI-ModelScope/Kokoro-82M-v1…

作者头像 李华
网站建设 2026/7/2 5:13:56

终端(PLC)上传数据到 JSON 字符串的转换适配器c#类

在我的plc上位机项目中&#xff0c;需要将 PLC 采集到的各种类型数据&#xff0c;统一转换为 JSON 接口需要的字符串格式&#xff0c;确保&#xff1a;数值格式固定&#xff08;不受服务器区域影响&#xff09;布尔值统一为 true/false&#xff08;而非 True/False 或 1/0&…

作者头像 李华