我试图在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"。