我得到一个八位字节(字节)和一些相关位,我想保留该给定字节的前n个(相关位)并将剩余的位设置为零。
E.g。
前4位相关的数字217将转换为 208
0 0
0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7
+-+-+-+-+-+-+-+ ==> +-+-+-+-+-+-+-+
1 1 0 1 1 0 0 1 1 1 0 1 0 0 0 0
前8个(或更多)位相关的数字255根本不会改变
0 0
0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7
+-+-+-+-+-+-+-+ ==> +-+-+-+-+-+-+-+
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
我写了这个函数来解决问题
(defun list-of-bits (integer)
(let ((bits '()))
(dotimes (position (integer-length integer) bits)
(push (ldb (byte 1 position) integer) bits))))
(defun calculate-octet (byte rel-bits)
(if (< rel-bits 8)
(parse-integer
(FORMAT nil "~{~a~}"
(replace (list-of-bits byte)
'(0 0 0 0 0 0 0 0)
:start1 rel-bits
:end1 8
:start2 0
:end2 rel-bits))
:radix 2)
byte))
但是这个解决方案看起来很糟糕有两个原因
它在处理之前将整数拆分为一个列表
它将列表打印成一个再次解析的字符串
我知道common-lisp提供了直接访问位和字节(ldb,logbitp)的函数,但我无法找到一种方法来将它们用于我的问题。
有没有办法更有效地解决问题(或至少更优雅)?
答案 0 :(得分:7)
CL-USER 6 > (mask-field (byte 4 4) 217)
208
另请注意,它不会屏蔽原始数字的字段,但会在屏蔽位字段时返回一个新数字。
答案 1 :(得分:6)
已有三个答案,所以我不妨再添两个:
还没有人建议DPB
。对PDP-10的点头总是很好。
(defun calculate-octet (byte bits)
(dpb 0 (byte bits bits) byte))
再次使用LOGAND
。
(defun calculate-octet (byte bits)
(logand byte (ash -1 (- 8 bits))))
答案 2 :(得分:2)
ash可以解决问题:
(defun calculate-octet (byte bits)
(let ((shift (- 8 bits)))
(ash (ash byte (- shift)) shift)))
测试:
? (calculate-octet 217 4)
208
? (calculate-octet 255 8)
255
答案 3 :(得分:0)
我认为你需要的是LOGAND。
(defun calculate-octet (byte rel-bits)
(ecase rel-bits
(0 0)
(1 (logand byte #b10000000))
(2 (logand byte #b11000000))
(3 (logand byte #b11100000))
(4 (logand byte #b11110000))
(5 (logand byte #b11111000))
(6 (logand byte #b11111100))
(7 (logand byte #b11111110))
(8 byte)))