我举了一个例子,试图向自己解释它的作用:
: place ptr len ptr2
2dup ptr len ptr2 len ptr2
>r >r ptr len ptr2
char+ ptr len (ptr2 + 1)
swap ptr (ptr2 + 1) len
chars ptr (ptr2 + 1) (len * char)
cmove --
from to how-many
r> r> ptr2 len
c! ; len = ptr2 ???
s" Hello! " name place
这一切都很有道理,直到最后一条指令。。。我哪里错了?
编辑:
我添加了一些跟踪:
: place ptr len ptr2 |
2dup cr .s ptr len ptr2 len ptr2 | <5> 16490736 5 2126333248 5 2126333248
>r >r cr .s ptr len ptr2 | <3> 16490736 5 2126333248
char+ cr .s ptr len (ptr2 + 1) | <3> 16490736 5 2126333249
swap cr .s ptr (ptr2 + 1) len | <3> 16490736 2126333249 5
chars cr .s ptr (ptr2 + 1) (len * char) | <3> 16490736 2126333249 5
cmove cr .s -- | <0>
from to how-many |
r> r> cr .s ptr2 len | <2> 5 2126333248 ok
c! ; ptr2 = len ??? |
s" Hello! " name place
我认为Will Hartung答案的第一部分是正确的。
正如他所描述的,正在使用的字符串表示,即字符计数,然后是实际字符串。
因此,在您的示例中,c!
将字符串的长度存储在以ptr2
开头的内存的第一个单元中。
因此,如果你想检索字符串,你只需要知道地址,然后你可以从该地址中提取长度n,并从地址+1开始提取n个字符。
在Forth中,至少在这种特定情况下,字符串的长度在内存中字符串的START处指定。例如,在C语言中,字符串是以0结尾的字节段。在Forth和Pascal等其他语言中,字符串有一个相关的长度,通常,在本例中,长度位于字符串的开头。
因此,对于字符串"HELLO",字节看起来像
05 H E L L O
字符串的开头指向其中包含5的字节
您的代码定位字符串,跳过长度(第一个char+
),然后为cmove
初始化它,这就完成了工作。
最后,它将长度复制到新字符串的开头。
例如,使用place
是错误的,因为您没有指定副本的长度。这需要将长度作为堆栈上的第二个参数。
所以,你的例子应该是:
s" Hello! " 7 name place 7 because of the space after the Hello!, the quote is the
delimiter, not the space. The leading spaces are ignored
奇怪的是,理论上不需要将长度传递给单词,它已经在字符串中了。如果要复制子集,则需要指定长度。
你也可以这样看。给定place
,你可以写一个简单的词:
: copy-string ( string-src dest -- )
>r string-src
dup string-src string-src
c@ string-src length
<r string-src length dest
place ;
因此:
s" Hello! " name copy-string
然后,你可以做:
: type-string ( string-src )
dup string-src string-src
c@ string-src length
type ; type out the string, type requires addr and length
因此:
create name 10 allot
s" Hello! " name copy-string
name type-string