使用GO语言将ASCII数字字符的字节数组转换为整数

16

我看到有些回答和我提出的完全相同的问题:如何在GO编程语言中将字节数组转换为整数?

我编写了下面的函数来将字节数组转换为整数

func convertByteToInt(in []byte) int32 {
    return  (int32(in[0]) << 24 | int32(in[1]) << 16 | int32(in[2]) << 8 | int32(in[3]))
}

在此之前,我确保字节数组具有正确的(256进制)值。 in [0] = 54(6的ASCII码), in [1] = 54(6的ASCII码), in [2] = 49(1的ASCII码), in [3] = 49(1的ASCII码)。

因此,我期望从字节数组中检索整数值6611,但最终得到了909521201。我无法理解在这样一个简单的转换中究竟发生了什么。 能否有人为我解惑?

谢谢


1
你有一个以十进制数字字符串格式化的整数,存储在[]byte中。将[]byte转换为字符串并使用strconv.Atoi和相关函数。在这里进行位操作是毫无意义的。(不值得回答。) - Volker
4个回答

15

@Volker在他的评论中说得对,你的数组中没有一个二进制数字,而是一个ASCII字符串。然而,你试图将其解码为二进制。请注意,如果你正在处理二进制数,则无需验证任何输入(也许除了长度),因为所有单字节值都是有效的。

@Ainar-G给出了一种将ASCII数字转换为整数的方法。

比较这两种方法: (http://play.golang.org/p/_wufZ4P_aE)

buf := []byte{54, 54, 49, 49}

x, _ := strconv.Atoi(string(buf))
fmt.Println(x)

这会输出6611;但是看看这个:

var y int32
_ = binary.Read(bytes.NewReader(buf), binary.BigEndian, &y)
fmt.Println(y)

这将打印909521201,与您获得的结果完全相同(但并非您所期望的)。另外需要注意的是,您手动将其解码为BigEndian,因此最终结果并不是“如此简单的转换”,因为还有一些其他因素需要考虑。

您自己制作的ASCII转换大致如下:

var x int32
for _, c := range in {
    x = x*10 + int32(c - '0')
}
return x

但是使用 strconv 是正确的方法。


2

将字节转换为字符串,然后使用 strconv.Atoi

b := []byte{54, 54, 49, 49}
s := string(b)
i, err := strconv.Atoi(s)
if err != nil {
    panic(err)
}
fmt.Println(i)

Playground: http://play.golang.org/p/NiobWHZ9gd


感谢您的回答。我已经用这些方法使它工作了。关于在GO中需要进行此类转换的原因,是因为GO是一种“严格类型”的语言,所以像C中那样的类型转换(通常使用void )在这里不可能吗?因为字节数组类似于C中的char/char[],通常用作发送/接收缓冲区。 - Korba
@Yogi,请检查我的答案。 - OneOfOne

1
如果你只需要将一个简单的正整数int值转换成[]byte,比如这个例子[]byte{'6', '6', '1', '1'}或者[]byte{54, 54, 49, 49}(它们是一样的),那么一个非常简单的for循环遍历[]byte并将其加到一个int中即可。就像这样:
var (
    myInt, i int
    myBytes = []byte{'6', '6', '1', '1'}
    v byte
)
for ; i < len(myBytes); i++ {
            v = myBytes[i] - '0'
            myInt *= 10
            myInt += int(v)
}

...就是这样。

Playground中查看完整的工作代码。


请问您能详细说明一下 v = myBytes[i] - '0' 是如何计算的吗?它实际上是做什么用的呢?谢谢。 - Chen A.
2
当你查看ASCII表时,这一点就会变得清晰明了。减去ASCII的'0'(十进制48)将48从字节值中减去。在上面的例子中,ASCII '6'实际上是字节54,如果你直接将字节移动到v中,它将具有字节的十进制值54,但你要找的是int值6而不是54对吧?那么你必须减去它的零值(ASCII '0' - 十进制48),54-48=6,这是字节54的int值。在游乐场里玩一下,它就会变得更清晰了。 - Victor Barrantes

1

在@tomasz的回答中,如果你想以二进制格式存储数字并且不关心字节序,你可以使用指针:

b := []byte{239, 190, 173, 222}
v := *(*uint32)(unsafe.Pointer(&b[0]))
fmt.Printf("0x%X\n", v)
fmt.Printf("%v", *(*[4]byte)(unsafe.Pointer(&v)))

playground

可以直接翻译为:

{{链接1:游乐场}}


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接