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



我试图在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不正确!我想我需要在福斯学习一些关于记忆管理的基本知识。

有人能解释一下这里出了什么问题,以及我应该做什么吗?

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

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

所以,我似乎需要在福斯自己管理记忆?如果是,如何?

解决方案

安德烈亚斯·邦贝提供了以下线索。最后一个可行的程序是

: make-string ( -- s )
  s" foo" ;
: append-print
  s+ type cr ;
make-string s" bar" append-print

输出为

$ gforth b.fs -e bye
foobar

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 +
;

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

Forth中字符串的使用在很大程度上不保证动态分配,至少在您的示例中不保证。您可以很好地使用ALLOT为自己分配的缓冲区以及一些非常简单的单词来操纵它们。

[ALLOT以增量的方式使用数据空间(ANSI术语)来添加单词和缓冲区。它不是动态的,你不能在不同时删除稍后分配的所有项目的情况下发布项目。它也很简单。不要与ALLOCATE混淆,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

其他福斯有其他非标准单词来操作简单字符串。穿越malloc土地的短途旅行真的没有必要。在gforth文档中,您可以查找"place"并找到一个等效的单词族。

同样在今天(2012年4月),你可以有这样的字符串"foo"。

相关内容

  • 没有找到相关文章