从word或变量追加字符串时出错

时间:2014-04-20 19:04:54

标签: forth gforth

我正在尝试在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

2 个答案:

答案 0 :(得分:1)

append在第一个字符串make空间上使用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 +
;

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

答案 1 :(得分:1)

在Forth中使用字符串并不能保证动态分配,至少在您的示例中也是如此。您可以很好地使用使用ALLOT分配的缓冲区 还有一些非常简单的词来操纵它们。

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

在遗漏append-buffer的规范时犯了一个根本性的错误。 它不起作用,我们也不知道它应该如何起作用!

在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文档中,您可以查找“位置”并找到同等的单词家族。

现在(2012年四月)您还可以使用类似“ foo”的字符串。