1

我正在尝试在 gforth 中附加两个字符串,但我收到了一些看起来很吓人的错误消息。

虽然s" foo" s" bar" append type cr工作正常,但一旦我开始将字符串存储在变量中或从单词中创建它们,就会出现错误。例如:

: make-string ( -- s )
    s" foo" ;

: append-print ( s s -- )
    append type cr ;

make-string s" bar" append-print

运行它会产生以下错误:

$ gforth prob1.fs -e bye
gforth(41572,0x7fff79cc2310) malloc: *** error for object 0x103a551a0: pointer being realloc'd was not allocated
*** set a breakpoint in malloc_error_break to debug

Abort trap: 6.

我精通C语言,所以很明显我错误地使用了Forth !我想我需要学习一些关于 Forth 内存管理的基本知识。

谁能解释一下这里出了什么问题,我应该怎么做?

当我尝试附加存储在变量中的字符串时,我也遇到了问题:

variable foo
s" foo" foo !

foo s" bar " append type cr

这以我必须打破的循环结束:

$ gforth prob2.fs
foo��^C
in file included from *OS command line*:-1
prob2.fs:4: User interrupt
foo s" bar " append >>>type<<< cr
Backtrace:
$10C7C2E90 write-file

作为参考,我在 Mac OS X 上使用 gforth 0.7.2。我将非常感谢您对正在发生的事情的一些很好的解释。

更新

我可以看到的定义append

see append
: append
  >l >l >l >l @local0 @local1 @local3 + dup >l resize throw >l @local4 @local0 @local3 + @local5
  move @local0 @local1 lp+!# 48 ; ok

那么,似乎我需要自己在 Forth 中管理内存?如果是这样,怎么做?

解决方案

Andreas Bombe 提供了以下线索。最终可行的程序是

: make-string ( -- s )
  s" foo" ;

: append-print
  s+ type cr ;

make-string s" bar" append-print

输出是

$ gforth b.fs -e bye
foobar
4

2 回答 2

1

append在第一个字符串上使用resize腾出空间来附加第二个字符串。这要求在堆上分配字符串。

当您将字符串编译s"成一个单词时,它会在字典中分配。如果您尝试resize(直接或间接通过append)该指针,您将看到您看到的错误。

通常s"具有未定义的解释语义。为了方便起见,Gforth 将其解释语义定义为在堆上分配字符串。这就是为什么只要你不编译它就可以工作(在 gforth 中)。

编辑:

我找到了 的定义append,它是libcc.fs(看起来是一个外来函数接口构建器)的一部分,而不是一个标准词。这是源码中的定义,比see反编译更易读:

: append { addr1 u1 addr2 u2 -- addr u }
    addr1 u1 u2 + dup { u } resize throw { addr }
    addr2 addr u1 + u2 move
    addr u ;

紧接在此之前的是 的定义s+

: s+ { addr1 u1 addr2 u2 -- addr u }
    u1 u2 + allocate throw { addr }
    addr1 addr u1 move
    addr2 addr u1 + u2 move
    addr u1 u2 +
;

如您所见,它分配了新的内存空间,而不是调整第一个字符串的大小并将两个字符串连接到其中。你可以改用这个。然而,它不是一个标准的词,只是恰好在您的环境中作为libcc.fsgforth 的内部实现细节,因此您不能依赖它在其他地方可用。

于 2014-04-25T23:34:40.393 回答
1

Forth 中字符串的使用主要不保证动态分配,至少在您的示例中不保证。你可以很好地使用你自己分配的缓冲区,使用 ALLOT 和一些非常简单的词来操作它们。

[ALLOT 以增量方式使用数据空间(ANSI 术语)来添加字和缓冲区。它不是动态的,您不能在不同时删除所有项目的情况下释放项目 ALLOT-ted 稍后。这也很简单。不要与 ALLOCATE 混淆,它是动态的并且在单独的扩展字集中]

您在遗漏附加缓冲区的规范方面犯了一个根本性错误。它不起作用,我们不知道它应该如何工作!

在 ciforth 的一个例子可能是:

 : astring S" foo" ;    

  CREATE buffer 100 ALLOT \ space for 100  chars 

  \ Put the first string in `buffer and append the second string.

  \ Also print the second string

 : append-print ( s s -- )

 type cr 2swap   

 buffer $!  

 buffer $+! ;   

 astring s" bar" append-print 

  bar OK \ answer

  buffer $@ TYPE 

  foobar OK \ answer

其他 Forths 有其他非标准的词来操作简单的字符串。真的没有必要在 malloc 土地上游览。在 gforth 文档中,您可以查找 'place' 并找到等价的词族。

同样现在(2012 年第四),您可以使用像“foo”这样的字符串。

于 2019-01-18T16:54:36.543 回答