我正在尝试在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
答案 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”的字符串。