Arrays 多字节存储和获取Forth-如何实现?
当使用大型阵列时,最好能够将阵列调整为每个数字的特定字节数。大多数情况下,我希望快速例程将调整后的多字节数读取到堆栈上的单字节,反之,将单字节存储在调整了一定字节数的数组中。在64位系统中,除了一个字节(c@c!)和八个字节(@!)之外,还需要其他单数字数组 那么如何实施呢Arrays 多字节存储和获取Forth-如何实现?,arrays,forth,gforth,Arrays,Forth,Gforth,当使用大型阵列时,最好能够将阵列调整为每个数字的特定字节数。大多数情况下,我希望快速例程将调整后的多字节数读取到堆栈上的单字节,反之,将单字节存储在调整了一定字节数的数组中。在64位系统中,除了一个字节(c@c!)和八个字节(@!)之外,还需要其他单数字数组 那么如何实施呢 cs@ ( ad b -- n ) cs! ( n ad b -- ) 其中b是字节数。cs这个词!看起来像 : cs! ( n ad b -- ) >r sp@ cell+ swap r> cmove dr
cs@ ( ad b -- n )
cs! ( n ad b -- )
其中b是字节数。cs这个词!看起来像
: cs! ( n ad b -- ) >r sp@ cell+ swap r> cmove drop ;
但是cs@如何,以及如何在没有sp@或类似单词的情况下在纯ANS-Forth中实现呢?兼容的方法是使用
C@
和按位操作。为了在内存中使用与Forth系统相同的字节顺序,需要检测endianness并编译特定定义的合适版本
\ These definitions use little-endian format in memory.
\ Assumption: char size and address unit size equal to 1 octet.
: MB! ( x addr u -- )
ROT >R OVER + SWAP
BEGIN 2DUP U> WHILE R> DUP 8 RSHIFT >R OVER C! 1+ REPEAT
2DROP RDROP
;
: MB@ ( addr u -- x )
0 >R OVER +
BEGIN 2DUP U< WHILE 1- DUP C@ R> 8 LSHIFT OR >R REPEAT
2DROP R>
;
在第二种情况下,我们不能使用?DO
,因为循环索引会减少,并且:当索引穿过“循环限制减1和循环限制之间的边界”时,它会离开圆圈
当然这里可以是任何一个单元格缓冲区
感谢ruvim解析前进的过程 Forth200*x*委员会花了相当长的时间开发了一个适合的单词集。由于其尺寸,我们尚未将其纳入标准。注意,
CS
代表控制流堆栈操作,如CS roll
等,请参阅。所以其他语义的后缀用法可能会混淆。是的,感觉很熟悉,但我没有想到。更好的名字可能是mb@和mb!如果单元格大小为64位,表达式addr@
必须给出与addr 8MB@
相同的结果吗?我的意思是,在这种情况下,cmove
可能会导致不同的结果。还要注意,在一般情况下,字节顺序在内存和堆栈上可能不同。不,这不是必需的。它只需要工作2-7个字节,不管怎样。速度是一件有趣的事情。@ruvim:64位系统2-7字节,32位系统2-3字节就好了。不使用do循环的想法是什么?@Lehs不使用do循环的想法是性能-我已经更新了答案。好主意-简短的解决方案!虽然,通过我的测试,这个解决方案的性能比使用do循环的解决方案差。还要注意的是,这些定义在big-endian的情况下是错误的。另外,mb@
应该在移动数据之前清除缓冲区。@ruvim:你说得对。这里应该被清除。什么是big-endian?最好不要在这里使用,以避免冲突,而是使用每线程缓冲区或返回堆栈上的缓冲区。关于big endian see@ruvim,我不确定你对big endian的看法是否正确。存储的相同模式也将被提取,与算术惯例无关。或者?使用big-endian0x332211地址3 mb代码>将执行:0x332211此处!(00 33 22 11是用mem写的)这里添加3 CMOVE(00 33 22是用mem写的)
。字节11丢失。这并不能回答这个问题。若要评论或要求作者澄清,请在其帖子下方留下评论。-如果你真的按照链接读了这篇文章,你会发现它不仅讨论了提供这些词的困难,而且还提供了22个词的集合的定义,使这篇文章更容易做到,以及验证这些词是否正确工作的单元测试。
: MB! ( x addr u -- )
OVER + SWAP ?DO DUP I C! 8 RSHIFT LOOP DROP
;
: MB@ ( addr u -- x )
DUP 0= IF NIP EXIT THEN
0 -ROT
1- OVER + DO 8 LSHIFT I C@ OR -1 +LOOP
;
\ little-endian (eg. pc, android)
: mb! ( n ad i -- ) 2>r here ! here 2r> cmove ;
: mb@ ( ad i -- n ) here 0 over ! swap cmove here @ ;
\ big-endian (eg. mac)
: mb! ( n ad i -- ) 2>r here ! here cell + r@ - 2r> cmove ;
: mb@ ( ad i -- n ) here 0 over ! cell + over - swap cmove here @ ;
\ little-endian test
1 here ! here c@ negate .