Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/arrays/14.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Arrays 多字节存储和获取Forth-如何实现?_Arrays_Forth_Gforth - Fatal编程技术网

Arrays 多字节存储和获取Forth-如何实现?

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

当使用大型阵列时,最好能够将阵列调整为每个数字的特定字节数。大多数情况下,我希望快速例程将调整后的多字节数读取到堆栈上的单字节,反之,将单字节存储在调整了一定字节数的数组中。在64位系统中,除了一个字节(c@c!)和八个字节(@!)之外,还需要其他单数字数组

那么如何实施呢

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-endian
0x332211地址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 .