有人把这个发给我,并声称它是 Brainfuck 中的一个 hello world(我希望如此......)

++++++++++[>+++++++>++++++++++>+++>+<<<<-]>++.>+.+++++++..+++.>++.<<+++++++++++++++.>.+++.------.--------.>+.>.

我知道它通过移动指针和递增和递减东西来工作的基础知识......

但我还是想知道,它实际上是如何工作的?它首先如何在屏幕上打印任何内容?它如何对文本进行编码?我完全不明白...

最佳答案

1. 基础知识

要理解 Brainfuck,您必须想象由 0 初始化的无限单元格数组。

...[0][0][0][0][0]...

当brainfuck 程序启动时,它指向任何单元格。
...[0][0][*0*][0][0]...

如果将指针向右移动 >,则将指针从单元格 X 移动到单元格 X+1
...[0][0][0][*0*][0]...

如果你增加单元格值 +,你会得到:
...[0][0][0][*1*][0]...

如果你再次增加单元格值 + 你会得到:
...[0][0][0][*2*][0]...

如果您减少单元格值 -,您会得到:
...[0][0][0][*1*][0]...

如果您将指针向左移动 <,您将指针从单元格 X 移动到单元格 X-1
...[0][0][*0*][1][0]...

2. 输入

要读取字符,请使用逗号 , 。它的作用是:从标准输入中读取字符并将其十进制 ASCII 代码写入实际单元格。

看看 ASCII table 。例如, ! 的十进制代码是 33 ,而 a97

好吧,让我们想象一下你的 BF 程序存储器是这样的:
...[0][0][*0*][0][0]...

假设标准输入代表 a ,如果你使用逗号 , 运算符,BF 所做的是读取 a 十进制 ASCII 码 97 到内存:
...[0][0][*97*][0][0]...

您通常想这样想,但事实要复杂一些。事实是 BF 不读取一个字符而是一个字节(无论那个字节是什么)。让我给你举个例子:

在 linux 中
$ printf ł

打印:
ł

这是特定的波兰特征。此字符不是通过 ASCII 编码进行编码的。在这种情况下,它是 UTF-8 编码,因此它曾经在计算机内存中占用一个以上的字节。我们可以通过做一个十六进制转储来证明:
$ printf ł | hd

这表现了:
00000000  c5 82                                             |..|

零是偏移的。 82 是第一个字节,c5 是第二个字节,代表 ł(为了我们将读取它们)。 |..| 是图形表示,在这种情况下是不可能的。

好吧,如果您将 ł 作为输入传递给读取单字节的 BF 程序,程序内存将如下所示:
...[0][0][*197*][0][0]...

为什么是 197 ?那么 197 十进制是 c5 十六进制。似曾相识?当然。它是 ł 的第一个字节!

3. 输出

要打印字符,请使用点 . 它的作用是:假设我们将实际单元格值视为十进制 ASCII 代码,将相应的字符打印到标准输出。

好吧,让我们想象一下你的 BF 程序存储器是这样的:
...[0][0][*97*][0][0]...

如果现在使用点 (.) 运算符,BF 所做的就是打印:



因为 ASCII 中的 a 十进制代码是 97

因此,例如这样的 BF 程序(97 加 2 个点):



将它指向的单元格的值增加到 97 并打印 2 次。



4. 循环

在 BF 循环中,由循环开始 [ 和循环结束 ] 组成。您可以认为这就像在 C/C++ 中,条件是实际单元格值。

看看下面的BF程序:
++[]
++ 将实际单元格值增加两次:
...[0][0][*2*][0][0]...

[] 就像 while(2) {} ,所以它是无限循环。

假设我们不希望这个循环是无限的。我们可以做例如:
++[-]

因此,每次循环循环时,它都会递减实际单元格值。一旦实际单元格值为 0 循环结束:
...[0][0][*2*][0][0]...        loop starts
...[0][0][*1*][0][0]...        after first iteration
...[0][0][*0*][0][0]...        after second iteration (loop ends)

让我们考虑另一个有限循环的例子:
++[>]

这个例子表明,我们还没有在循环开始的单元格处完成循环:
...[0][0][*2*][0][0]...        loop starts
...[0][0][2][*0*][0]...        after first iteration (loop ends)

然而,在我们开始的地方结束是一种很好的做法。为什么 ?因为如果循环结束它开始的另一个单元格,我们不能假设单元格指针将在哪里。老实说,这种做法让brainfuck 少了brainfuck。

关于brainfuck - Brainfuck Hello World 是如何工作的?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/16836860/

10-12 21:07