将静态分配的字符串复制到动态分配的字符串

时间:2013-08-08 22:07:33

标签: string memory-management forth

我关注example,试图向自己解释它的作用:

: 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

2 个答案:

答案 0 :(得分:1)

在Forth中,至少在这种特定情况下,字符串的长度在内存中String的START处指定。例如,在C中,字符串是以0结尾的字节段。在Forth中,在Pascal等其他语言中,字符串与它们具有相关的长度,并且通常,如在这种情况下,长度是在开头的字符串。

因此,对于字符串“HELLO”,字节看起来像

05 H E L L O

字符串的开头指向字节,其中包含5。

你的代码找到了字符串,跳过了长度(第一个char+),然后为cmove填充它,这就完成了工作。

最后,它将长度复制到新String的开头。

例如,使用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

关于这一点的奇怪之处在于理论上没有必要将长度传递给单词,它已经存在于String中。如果要复制子集,可以指定长度。

你也可以这样看待它。鉴于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

答案 1 :(得分:1)

我认为Will Hartung的答案的第一部分是正确的。

正在使用的字符串表示符如他所描述的,即字符计数,然后是实际的字符串。

因此,在您的示例c!中,将字符串的长度存储在以ptr2开头的内存的第一个单元格中。

因此,如果您想要检索字符串,您只需要知道地址,然后可以从该地址获取以获取长度n,并从地址+ 1开始获取n个字符。