
本文深入探讨了在golang中如何进行字符与数值的转换及算术运算,特别是针对十六进制求和的常见误区。我们将首先澄清字符与字符串十六进制表示的区别,并演示正确的字符算术方法。随后,文章将详细介绍如何实现astm校验和(checksum)的计算,包括其核心逻辑和完整的go语言代码实现,旨在帮助开发者准确处理数据帧的校验需求。
Golang中的字符与数值运算
在Golang中,字符(character)本质上是整数类型。单个字符字面量,例如 'a',其类型是 rune(实际上是 int32 的别名,用于表示Unicode码点),而当它作为字符串中的一个字节被访问时,则是一个 byte(uint8 的别名)。这意味着我们可以直接对字符进行算术运算,因为它们代表的是其对应的ASCII或Unicode数值。
许多开发者在尝试对字符的“十六进制值”进行求和时,可能会误用 fmt.Sprintf("%x", "a") 这样的方法。然而,fmt.Sprintf("%x", "a") 的结果是一个字符串 "61",它仅仅是字符 'a' 的ASCII码(0x61)的字符串表示,而非一个可用于算术的数值。直接将字符串 "61" 与其他数值相加会导致类型错误。
正确的做法是直接使用字符的数值。例如,要将字符 'a' 的数值与 0x01 相加,并得到结果字符 'b',可以这样做:
package main
import "fmt"
func main() {
// 获取字符 'a' 的码点值,即 0x61
val := 'a' // val 的类型是 rune (int32)
// 将 0x61 与 0x01 相加,结果为 0x62
// 然后将数值 0x62 转换回字符,即 'b'
fmt.Printf("%v\n", string(val + 0x01)) // 输出: b
}这段代码展示了Go语言中字符与整数运算的直观性。字符 'a' 的底层数值是 97(十进制)或 0x61(十六进制),对其进行加法运算后,再通过 string() 转换回字符,即可得到预期的结果。
立即学习“go语言免费学习笔记(深入)”;
ASTM 校验和计算原理
ASTM(American Society for Testing and Materials)是一种广泛应用于医疗、工业等领域的数据传输标准。其定义的校验和(Checksum)是一种简单而有效的错误检测机制,用于确保数据在传输过程中的完整性。ASTM校验和的基本计算规则如下:
- 起始标志 (STX):当遇到 STX (Start of Text, 0x02) 字符时,校验和的累加器会被重置为零。
- 累加范围:校验和的计算通常包括 STX 之后到 ETX (End of Text, 0x03) 或 ETB (End of Transmission Block, 0x17) 之前的所有字符的字节值。
- 累加方式:将范围内每个字符的字节值累加到校验和中。
- 终止标志 (ETX/ETB):当遇到 ETX 或 ETB 字符时,累加过程停止。这些终止字符本身通常不包含在最终的校验和计算中,但它们标志着校验和计算的结束点。
- 结果:最终的校验和通常表示为一个两位十六进制数。
在Go语言中实现ASTM校验和
根据上述原理,我们可以实现一个 ASTMCheckSum 函数来计算给定字符串的ASTM校验和。我们需要定义一些常量来表示控制字符,并遍历输入字符串的字节,根据规则累加和处理。
package main
import (
"fmt"
)
const (
STX byte = 0x02 // Start of Text
ETX byte = 0x03 // End of Text
ETB byte = 0x17 // End of Transmission Block
)
// ASTMCheckSum 计算给定字符串的ASTM校验和
func ASTMCheckSum(frame string) string {
var sumOfChars uint8 // 使用 uint8 确保和在 0-255 之间循环
// 遍历字符串中的每个字节
for i := 0; i < len(frame); i++ {
byteVal := frame[i] // 获取当前字节值
// 如果遇到 STX,重置校验和
if byteVal == STX {
sumOfChars = 0
}
// 累加当前字节值
sumOfChars += byteVal
// 如果遇到 ETX 或 ETB,停止累加并跳出循环
if byteVal == ETX || byteVal == ETB {
break
}
}
// 将最终的校验和格式化为两位大写十六进制字符串
return fmt.Sprintf("%02X", sumOfChars)
}
func main() {
// 示例数据帧,包含 STX (\x02) 和 ETX (\x03)
data := "\x025R|2|^^^1.0000+950+1.0|15|||^5^||V||34001637|20080516153540|20080516153602|34001637\r\x033D\r\n"
// 计算并打印校验和
fmt.Println(ASTMCheckSum(data)) // 预期输出: 3D
}在上述代码中:
- 我们定义了 STX、ETX 和 ETB 为 byte 类型的常量,以便与字符串中的字节值直接比较。
- sumOfChars 被声明为 uint8。这是一个关键点,因为 uint8 的最大值是 255。当累加的和超过 255 时,它会自动“溢出”并从 0 重新开始(例如 255 + 1 = 0),这正是许多校验和算法(包括ASTM)所需的模 256 运算效果。
- 循环遍历 frame 字符串的每个字节。Go语言的字符串在迭代时,frame[i] 会直接返回对应位置的 byte 值。
- 根据ASTM规则,如果遇到 STX,sumOfChars 会被重置。
- 每个字节都被累加到 sumOfChars 中。
- 一旦遇到 ETX 或 ETB,循环立即终止,不再处理后续字符。
- 最后,使用 fmt.Sprintf("%02X", sumOfChars) 将 uint8 类型的校验和格式化为两位大写的十六进制字符串。%02X 确保输出始终是两位,不足两位时前面补零。
注意事项与总结
- 字符与字节的区别:在Go语言中,理解字符(rune)和字节(byte)以及它们与字符串表示形式(如十六进制字符串)之间的关系至关重要。直接对字符进行算术运算操作的是其底层数值,而不是其字符串形式。
- 校验和类型:选择正确的整数类型(如 uint8)对于实现模运算的校验和算法非常重要,它可以避免手动进行模运算。
- 控制字符处理:ASTM校验和算法对 STX、ETX 和 ETB 等控制字符有特殊处理规则(重置、终止),务必在实现中准确遵循。
- 编码一致性:当处理包含非ASCII字符的字符串时,确保所有参与校验和计算的系统都使用相同的字符编码(通常是UTF-8),以避免字节值不匹配的问题。
通过本文的讲解和示例,您应该能够清晰地理解Go语言中字符的数值运算,并掌握如何根据ASTM标准实现一个可靠的数据校验和计算功能。










