我对类型“c”的二进制扫描感到困惑,因为据说“c”指的是8位字符代码。我有以下代码要维护
puts ""
set b_val2 "0000021002020a042845245d868a8d9900081b000315aef0010c105d39b4f7c9a083a65e7d000306140508063024"
set msg2 [binary format H* $b_val2]
set msg2 [string range $msg2 1 end]
while {[binary scan $msg2 cc id2 len2] == 2} {
puts ""
#puts "SECOND ID is $id2 and SECOND LENGTH is $len2"
set id2 [expr {$id2 & 0xff}]
set len2 [expr {$len2 & 0xff}]
set val2 [string range $msg2 2 [expr {1+$len2}]]
switch -exact -- $id2 {
0 {
puts ""
if {$val2 == "\x10\x04"} {
puts "val is found for 04 "
} elseif {$val2 == "\x10\x02"} {
puts "ID is found for 02! CORRECT "
} else {
puts "not supported"
}
}
}
}
这个想法是从给定的十六进制中取“10 02”的值。并且这段代码工作正常,直到我将b_val的给定输入更改为
00021002020903e845245ca0d29858081c00031ef7c001106d3931e7d3414e6d3df26831030614051608045c22
对于第一个给定的十六进制代码“len”是“3”并且它正确地解析二进制文件,但对于第二个十六进制输入,“len2”是16,因此解析错误的字节。
我读到二进制扫描cc将返回两个8位字符代码的变量,但上面的失败根本没有任何意义,正如我所理解的那样,前一作者试图瞄准的是什么上面的代码(特别是它尝试取范围的set val2)以及第二次输入失败的原因
答案 0 :(得分:1)
对于初学者:您的代码段永远不会在msg2
循环中修改while
,因此scan
会在每个循环中返回相同的结果,并且您有一个无限循环。我抛出一个break
只进行一次循环,但这让我不确定我是否有正确的行为。
尽管如此,显而易见的问题是,当您从原始消息转到替换消息时,您已删除了第一个字节(值为00)。从第2行(忽略空白行)开始,在此处设置
set b_val2 "0000021002020a..."
让我们手工解析。第3行将其转换为十六进制,第4行删除第一个字节,以便我们以十六进制值\x00 \x02 \x10 \x02 \x02 \x0a ...
的字节串开头。第5行的binary scan
将id2设置为第一个字节,将len2设置为第二个字节;第10行将val2设置为值为\x10 \x02
的字符串,该字符串符合您的条件。成功。
现在使用
的输入进行重新分析set b_val2 "00021002020903e84..."
来自您的第二个输入行。同样,第4行的第一个字节是DISCARDED,只剩下\x02 \x10 \x02 \x02 \x09 \x03...
。第5行将id2设置为2,将len2设置为\x10
或十进制16,这是您所看到的。这意味着val2与您的预期非常不同,但这是由于您从输入中删除了一个字节。
字节解析器对字符串中的初始位置非常敏感。一旦你搞砸了,你最好有一个强大的重新同步机制,或者它完全禁止喊叫。这是线路协议困难的一个主要原因。 :)