我需要从整数列表中生成一个字节串(按顺序 通过套接字连接将它们发送到C程序)。我正在尝试复制一些使用'struct'模块的Python代码。下面的Python代码产生了这个输出:
import struct
struct.pack('HHHH', 1, 2, 3, 4)
-->
'\x01\x00\x02\x00\x03\x00\x04\x00'
等效的Lisp代码产生以下输出:
(ql:quickload :pack)
(pack:pack "HHHH" 1 2 3 4)
-->
#(1 0 2 0 3 0 4 0)
如何将此数组转换为字符串格式,并使用与Python代码相同的表示形式?
非常感谢,
大卫
答案 0 :(得分:3)
当你说"字节串"时,语句是不精确的。在CL中,字符串是字符的向量。字符没有指定的大小。今天大多数Common Lisp实现都使用普通的Unicode代码点来表示字符,这意味着每个字符的大小至少为21位(但通常为32位)。
你可能想要的是一个8位字节的向量。它们的Lisp类型为(VECTOR (UNSIGNED-BYTE 8) *)
。
因此,将数字列表转换为此类向量的最简单方法是使用:
(coerce '(1 2 3 4) '(vector (unsigned-byte 8)))
但是,您可能实际上并不需要这样做,因为只要将流的元素类型设置为正确的类型,就会自动处理。我不知道您使用什么API来打开网络连接,但如果您使用的是usocket,那么正确的形式是:
(usocket:socket-connect host port :element-type '(unsigned-byte 8))
然后,您可以使用WRITE-SEQUENCE
将您的号码列表直接写入流中,它们将按照您的预期以字节形式发送。
最后,我想解释为什么你的字符串技巧可能有效。可能发生的是您将流打开为字符流,这会导致您的字符串使用某些特定的编码进行编写。大多数字符串编码都是ASCII兼容的(例如,UTF-8),这意味着0-127范围内的任何字节都将作为该字节发送,而大于127的值可能会导致各种不可预测的值(除非您的编码是ISO 8859-1,其中最大255的值也是正确的)。依靠字符串编码来发送二进制数据是一个非常糟糕的主意,我建议您在发送二进制数据时使用适当的二进制流。
答案 1 :(得分:2)
将字节数组转换为字符串的一种非常简单的方法是使用map
预定义函数:
(map 'string #'code-char (pack:pack "HHHH" 1 2 3 4))