当前位置: 首页 > 知识库问答 >
问题:

脑力操Hello世界到底是怎么运作的?

安奇
2023-03-14

有人给我发了这个,声称这是Brainfuck中的hello world(我希望如此…)

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

我知道它的基本原理是通过移动指针和递增或递减来工作。。。

但我还是想知道,它到底是如何工作的?它首先是如何在屏幕上打印任何东西的?它是如何编码文本的?我完全不明白。。。

共有3个答案

慕皓君
2023-03-14

Brainfuck和它的名字一样。它只使用8个字符

它以数组形式存储值:[72][101][108][111]

let,最初指向数组单元格1的指针:

>

<代码>

将单元格的值增加1

-将元素的值增加1

打印当前单元格的值。

将输入输入到当前单元格。

[]循环,[-]计数器的3个计数bcz它前面有3′,并且-将计数变量递减1个值。

存储在单元格中的值是ascii值:

参考上面的数组:[72][101][108][108][111],如果你匹配ascii值,你会发现它是Hello Writern

恭喜!你已经学会了BF的语法

---更多的东西---

让我们制作我们的第一个程序,即Hello World,之后你可以用这种语言写下你的名字。

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

碎裂:

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

创建一个4个单元格的数组

array =[7,10,3,1]
i=10
while i>0:
 element +=element
 i-=1

因为计数器值存储在单元格0和

<代码>

因此,在循环完成后,我们有了数组:[70100,30,10]

>++. 

移动到第1个元素并将其值增加2(两个“”),然后用该ascii值打印(“.”)字符。i、 例如python中的e:chr(702)#打印'H'

>+.

移动到第二个单元格增量1,使其值为100 1,并打印('.')其值,即chr(101)chr(101)#打印'e'现在没有

+++++ ++..

因此,最新元素=101,101 7并打印两次(因为有两个“…”)chr(108)#打印l两次可以用作

for i in array:
    for j in range(i.count(‘.’)):
           print_value

---在哪里使用---

它只是一种用来挑战程序员的玩笑语言,实际上并不在任何地方使用。

公羊伟志
2023-03-14

维基百科有一个注释版本的代码。

+++++ +++++             initialize counter (cell #0) to 10
[                       use loop to set the next four cells to 70/100/30/10
    > +++++ ++              add  7 to cell #1
    > +++++ +++++           add 10 to cell #2 
    > +++                   add  3 to cell #3
    > +                     add  1 to cell #4
    <<<< -                  decrement counter (cell #0)
]                   
> ++ .                  print 'H'
> + .                   print 'e'
+++++ ++ .              print 'l'
.                       print 'l'
+++ .                   print 'o'
> ++ .                  print ' '
<< +++++ +++++ +++++ .  print 'W'
> .                     print 'o'
+++ .                   print 'r'
----- - .               print 'l'
----- --- .             print 'd'
> + .                   print '!'
> .                     print '\n'

要回答您的问题,字符用于I/O。文本是ASCII。

维基百科的文章也进行了更深入的讨论。

第一行通过简单地从0递增十倍来初始化a[0]=10。第2行的循环有效地设置了数组的初始值:a[1]=70(接近72,字符“H”的ASCII代码)、a[2]=100(接近101或“e”)、a[3]=30(接近32,空格代码)和a[4]=10(换行)。循环的工作原理是每次通过循环分别向a[1]a[2]a[3]a[4]单元格添加7、10、3和1,每个单元格总共添加10次(给出a[1]=70等)。循环完成后,a[0]为零<代码>

下一行将数组指针移动到a[2]并向其中添加一个指针,生成101,即小写字母“e”,然后输出。

由于'l'恰好是'e'之后的第七个字母,为了输出'll',在a[2]中添加另外七个(),结果输出两次。

“o”是“l”之后的第三个字母,因此a[2]再递增三次并输出结果。

程序的其余部分以同样的方式进行。对于空格和大写字母,选择不同的阵列单元,并根据需要递增或递减。

奚修伟
2023-03-14

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

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

当brainfuck程序启动时,它指向任何细胞。

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

如果你向右移动指针

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

如果增加单元格值,则会得到:

...[0][0][0][*1*][0]...

如果再次增加单元格值,则会得到:

...[0][0][0][*2*][0]...

如果减少单元格值-,则会得到:

...[0][0][0][*1*][0]...

如果向左移动指针

...[0][0][*0*][1][0]...

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

看看ASCII表。例如,的十进制代码 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十六进制。看起来很熟悉吗?当然。这是的第一个字节!

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

让我们想象一下你的BF程序内存是这样的:

...[0][0][*97*][0][0]...

如果使用点(.)接线员现在BF要做的是打印:

A.

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

比如像这样的BF程序(97加2点):

..

将其指向的单元格的值增加到97,并打印两次。

AA级

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

看看下面的BF程序:

++[]

将实际单元格值增加两次:

...[0][0][*2*][0][0]...

[]类似于而(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)

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

 类似资料:
  • 以下代码片段来自维基百科,是标准Hello World的序言!Brainfuck中的程序。。。 我理解这里发生的事情的要点,但是我不明白的是第3行到第6行发生的事情的机制。如果给中的值增加10,为什么将指针增加1并执行7次会导致等于70?难道不应该吗?看起来通过神奇地增加了10倍,我不明白为什么。

  • 4.2. Hello,世界 让我们从经典的"Hello, World"程序开始: 05 package main 07 import fmt "fmt" // Package implementing formatted I/O. 09 func main() { 10 fmt.Printf("Hello, world; or Καλημ?ρα

  • > < li> 如何生成“304未修改”响应? 浏览器如何确定对HTTP请求的响应是否为304? 是浏览器设置的还是服务器发来的 如果由服务器发送,服务器如何知道缓存中可用的数据,以及如何将304设置为图像? 我猜,如果它是由浏览器生成的: 我依靠第三方API提供商来获取数据,解析 我想使用相同类型的算法来确定数据的变化。

  • 我们为项目创建了一个package.json文件。 现在我们将使用Electron创建我们的第一个桌面应用程序。 创建一个名为main.js的新文件。 在其中输入以下代码 - const {app, BrowserWindow} = require('electron') const url = require('url') const path = require('path') let

  • 为了测试你的安装,我们创建一个简单的应用程序hello world.打开Qt Creator并且创建一个Qt Quick UI Project(File->New File 或者 Project-> Qt Quick Project -> Qt Quick UI)并且给项目取名 HelloWorld。 注意 Qt Creator集成开发环境允许你创建不同类型的应用程序。如果没有另外说明,我们都创建

  • 在这个例子中,我们将创建一个基于Spring Boot + MVC + Rest的Web应用程序。 第1步:创建源文件夹 在E:\Test folder.创建文件夹FirstApplication E:\Test folder. 第2步:创建源文件 使用以下源代码在E:\Test folder创建FirstApplication.groovy文件 - @RestController class F