要将 Brainfly 这个字符串用 C 语言表示,你可以将其存储在一个字符数组中。以下是如何在 C 语言中声明并初始化一个包含 Brainfly 字符串的字符数组的示例代码:```c#include int main() {char brainfly[]

摘要:Brainfuck 简介 Brainfuck 是由 Urban Müller 在 1993 年创造的一门非常精简的图灵完备的编程语言。 正所谓大道至简,这门编程语言简单到语法只有 8 个字符,每一个字符对应一个指令
Brainfuck 简介 Brainfuck 是由 Urban Müller 在 1993 年创造的一门非常精简的图灵完备的编程语言。 正所谓大道至简,这门编程语言简单到语法只有 8 个字符,每一个字符对应一个指令,用 C 语言来描述的话就是: 字符 含义 > ++ptr < --ptr + ++*ptr - --*ptr . putchar(*ptr) , *ptr = getchar() [ while (*ptr) { ] } 然后只需要提供一个已经初始化为 0 的字节数组作为内存、一个指向数组的指针、以及用于输入输出的两个字节流就能够让程序运行了。 比如 Hello World! 程序就可以写成: ++++++++++[>+++++++>++++++++++>+++>+<<<<-] >++.>+.+++++++..+++.>++.<<+++++++++++++++. >.+++.------.--------.>+.>. C# 类型系统入门 既然要用 C# 类型系统来构建 Brainfuck 的编译器,我们需要首先对 C# 类型系统有一些认知。 泛型系统 C# 的类型系统构建在 .NET 的类型系统之上,而众所周知 .NET 是一个有具现化泛型的类型系统的平台,意味着泛型参数不仅不会被擦除,还会根据泛型参数来分发甚至特化代码。 例如: class Foo<T> { public void Print() => Console.WriteLine(default(T)?.ToString() ?? "null"); } 对于上面的代码,调用 new Foo<int>().Print() 会输出 0,调用 new Foo<DateTime>().Print() 会输出 0001-01-01T00:00:00,而调用 new Foo<string>().Print() 则会输出 null。 更进一步,因为 .NET 泛型在运行时会根据类型参数对代码进行特化,比如: class Calculator<T> where T : IAdditionOperators<T, T, T> { public T Add(T left, T right) { return left + right; } } 我们可以前往 godbolt 看看 .NET 的编译器对上述代码产生了什么机器代码: Calculator`1[int]:Add(int,int):int:this (FullOpts): lea eax, [rsi+rdx] ret Calculator`1[long]:Add(long,long):long:this (FullOpts): lea rax, [rsi+rdx] ret Calculator`1[ubyte]:Add(ubyte,ubyte):ubyte:this (FullOpts): add edx, esi movzx rax, dl ret Calculator`1[float]:Add(float,float):float:this (FullOpts): vaddss xmm0, xmm0, xmm1 ret Calculator`1[double]:Add(double,double):double:this (FullOpts): vaddsd xmm0, xmm0, xmm1 ret 可以看到我代入不同的类型参数进去,会得到各自特化后的代码。 接口的虚静态成员 你可能好奇为什么上面的 Calculator<T> 里 left 和 right 可以直接加,这是因为 .NET 支持接口的虚静态成员。
阅读全文