TCL 中的二进制格式化变量

Binary Formatting Variables in TCL

我正在尝试创建一个二进制消息以通过套接字发送,但我遇到了 TCL 将所有变量视为字符串的方式。我需要计算字符串的长度并知道它的二进制值。

set length [string length $message]
set binaryMessagePart [binary format s* { $length 0 }]

但是,当我 运行 这样做时,我得到了错误 'expected integer but got "$length"'。我如何让它工作以及 return 整数 5 而不是 char 5 的值?

要计算字符串的长度,请使用 string length。要计算特定编码中字符串的长度,请将字符串转换为该编码并使用 string length:

set enc "utf-8";  # Or whatever; you need to know this ahead of time for sanity's sake
set encoded [encoding convertto $enc $message]
set length [string length $encoded]

请注意,对于编码长度,这将以字节为单位,而编码之前的长度以字符为单位。对于某些消息和某些编码,差异可能很大。

要使用消息的长度和正文(一种相当常见的二进制格式)组成二进制消息,请像这样使用 binary format

# Assumes the length is big-endian; for little-endian, use i instead of I
set binPart [binary format "Ia*" $length $encoded]

你做错了什么是使用 s* 它消耗一个整数列表并在输出字符串中产生一个 little-endian 短整数二进制值序列,但正在提供列表字面上 $length 0; string $length 不是整数,因为它们不是以 $ 开头的。我们本可以改为 [list $length 0] 来生成 s* 的论点,这会奏效,但对于问题的上下文来说,这似乎不太正确。

binary format中,这些是常用的格式(还有很多):

  • a 用于字符串数据(助记“ASCII”);这是二进制字符串数据,您需要先对其进行编码。
  • iI 用于 32 位数字(助记“int”,就像在许多编程语言中一样,但尤其是 C)。大写为big-endian,小写为little-endian.
  • sS 用于 16 位数字(助记“short”)。
  • c 用于 8 位数字(来自 C 的助记符“char”)。
  • wW 用于 64 位数字(助记“宽整数”)。
  • fd 用于 IEEE 二进制浮点数(助记符分别为“float”和“double”,所以 4 和 8 个字节)。

All 后面可以跟一个可选的长度,可以是数字或 *。对于数字,不是插入单个数字,而是插入它们的列表(因此消耗列表);数字给出固定长度,* 给出“所有列表”。对于字符串格式指示符,数字在消息中使用固定数量的字节(根据需要用零字节截断或填充)并且 * 执行“所有字符串”(从不截断或填充)。