目录

Go语言中不同进制的互转方法:二进制/八进制/十六进制互转方法

作为 Go 开发者,日常开发中难免会遇到进制转换的需求 —— 比如处理网络协议中的二进制数据、配置文件中的十六进制参数、日志中的八进制权限值等。

Go 标准库中的strconv包提供了完善的进制转换工具,无需手动实现复杂算法,就能轻松完成二进制、八进制、十六进制与十进制的互转。

本文结合实际开发场景,详细拆解各类进制转换的实现逻辑、代码示例及避坑指南,让你彻底掌握 Go 语言的进制操作

一、二进制与十进制互转(常用)

二进制以0b为前缀,十进制是默认进制,两者互转是基础中的基础。

(一)二进制字符串 → 十进制整数

使用strconv.ParseInt(),指定base=2(表示输入字符串是二进制),bitSize根据需求选择(8/16/32/64,对应 int8/int16/int32/int64)。

package main

import (
	"fmt"
	"strconv"
)

func main() {
	// 二进制字符串(可带0b前缀,也可不带)
	binStr1 := "1010"   // 不带前缀,等价于10
	binStr2 := "0b1101" // 带0b前缀,等价于13

	// 转换:base=2表示二进制,bitSize=64表示转成int64
	dec1, err := strconv.ParseInt(binStr1, 2, 64)
	if err != nil {
		fmt.Printf("二进制转十进制失败:%v\n", err)
	} else {
		fmt.Printf("二进制%s → 十进制:%d\n", binStr1, dec1) // 输出:1010 → 10
	}

	// 带前缀的二进制字符串转换(注意:base=2时,前缀0b会被自动忽略,无需手动处理)
	dec2, err := strconv.ParseInt(binStr2, 2, 64)
	if err != nil {
		fmt.Printf("二进制转十进制失败:%v\n", err)
	} else {
		fmt.Printf("二进制%s → 十进制:%d\n", binStr2, dec2) // 输出:0b1101 → 13
	}
}

(二)十进制整数 → 二进制字符串

使用strconv.FormatInt(),指定base=2,返回的字符串默认不带0b前缀(如需前缀可手动拼接)。

func main() {
	dec := 25 // 十进制25
	// 十进制转二进制(不带前缀)
	binStr := strconv.FormatInt(int64(dec), 2)
	fmt.Printf("十进制%d → 二进制(无前缀):%s\n", dec, binStr) // 输出:11001

	// 十进制转二进制(带0b前缀)
	binStrWithPrefix := "0b" + strconv.FormatInt(int64(dec), 2)
	fmt.Printf("十进制%d → 二进制(带前缀):%s\n", dec, binStrWithPrefix) // 输出:0b11001
}

二、十进制与八进制互转

权限配置常用

八进制以0为前缀(Go 中八进制字面量必须带0),常用于表示文件权限(如0755)。

(一)八进制字符串 → 十进制整数

使用strconv.ParseInt(),指定base=8,注意输入字符串可带0前缀或不带。

func main() {
	octStr1 := "12"    // 不带前缀,等价于十进制10
	octStr2 := "0755"  // 带0前缀,文件权限常用,等价于十进制493

	// 不带前缀转换
	dec1, err := strconv.ParseInt(octStr1, 8, 64)
	if err != nil {
		fmt.Printf("八进制转十进制失败:%v\n", err)
	} else {
		fmt.Printf("八进制%s → 十进制:%d\n", octStr1, dec1) // 输出:12 → 10
	}

	// 带前缀转换(base=8时,前缀0会被自动忽略)
	dec2, err := strconv.ParseInt(octStr2, 8, 64)
	if err != nil {
		fmt.Printf("八进制转十进制失败:%v\n", err)
	} else {
		fmt.Printf("八进制%s → 十进制:%d\n", octStr2, dec2) // 输出:0755 → 493
	}
}

(二)十进制整数 → 八进制字符串

使用strconv.FormatInt(),指定base=8,返回字符串默认不带0前缀(如需前缀手动拼接)。

func main() {
	dec := 493 // 十进制493,对应文件权限0755
	// 不带前缀
	octStr := strconv.FormatInt(int64(dec), 8)
	fmt.Printf("十进制%d → 八进制(无前缀):%s\n", dec, octStr) // 输出:755

	// 带0前缀(文件权限场景常用)
	octStrWithPrefix := "0" + strconv.FormatInt(int64(dec), 8)
	fmt.Printf("十进制%d → 八进制(带前缀):%s\n", dec, octStrWithPrefix) // 输出:0755
}

三、十六进制与十进制互转

数据传输常用

十六进制以0x为前缀,常用于表示字节数据(如0xFF)、哈希值(如 MD5 结果)等场景。

(一)十六进制字符串 → 十进制整数

使用strconv.ParseInt(),指定base=16,输入字符串可带0x前缀或不带,支持大小写字母(A-F/a-f)。

func main() {
	hexStr1 := "1A"     // 不带前缀,等价于十进制26
	hexStr2 := "0xFF"   // 带0x前缀,等价于十进制255
	hexStr3 := "0xa3"   // 小写字母,等价于十进制163

	dec1, err := strconv.ParseInt(hexStr1, 16, 64)
	if err != nil {
		fmt.Printf("十六进制转十进制失败:%v\n", err)
	} else {
		fmt.Printf("十六进制%s → 十进制:%d\n", hexStr1, dec1) // 输出:1A → 26
	}

	dec2, err := strconv.ParseInt(hexStr2, 16, 64)
	if err != nil {
		fmt.Printf("十六进制转十进制失败:%v\n", err)
	} else {
		fmt.Printf("十六进制%s → 十进制:%d\n", hexStr2, dec2) // 输出:0xFF → 255
	}

	dec3, err := strconv.ParseInt(hexStr3, 16, 64)
	if err != nil {
		fmt.Printf("十六进制转十进制失败:%v\n", err)
	} else {
		fmt.Printf("十六进制%s → 十进制:%d\n", hexStr3, dec3) // 输出:0xa3 → 163
	}
}

(二)十进制整数 → 十六进制字符串

使用strconv.FormatInt(),指定base=16,返回字符串默认小写(如需大写可使用strings.ToUpper()),不带0x前缀。

import "strings"

func main() {
	dec := 255 // 十进制255
	// 小写不带前缀
	hexStrLower := strconv.FormatInt(int64(dec), 16)
	fmt.Printf("十进制%d → 十六进制(小写):%s\n", dec, hexStrLower) // 输出:ff

	// 大写带0x前缀(哈希值场景常用)
	hexStrUpper := "0x" + strings.ToUpper(strconv.FormatInt(int64(dec), 16))
	fmt.Printf("十进制%d → 十六进制(大写带前缀):%s\n", dec, hexStrUpper) // 输出:0xFF
}

四、跨进制直接互转

无需经过十进制

上述方法都是以十进制为桥梁,但部分场景下可直接实现二进制、八进制、十六进制的互转

本质是 “目标进制→十进制→目标进制” 的简化写法,代码更简洁。

(一)二进制 → 十六进制

func main() {
	binStr := "11010110" // 二进制字符串
	// 步骤1:二进制转十进制
	dec, err := strconv.ParseInt(binStr, 2, 64)
	if err != nil {
		fmt.Printf("转换失败:%v\n", err)
		return
	}
	// 步骤2:十进制转十六进制(大写带前缀)
	hexStr := "0x" + strings.ToUpper(strconv.FormatInt(dec, 16))
	fmt.Printf("二进制%s → 十六进制:%s\n", binStr, hexStr) // 输出:11010110 → 0xD6
}

(二)十六进制 → 八进制

func main() {
	hexStr := "0x1A3" // 十六进制字符串
	// 步骤1:十六进制转十进制
	dec, err := strconv.ParseInt(hexStr, 16, 64)
	if err != nil {
		fmt.Printf("转换失败:%v\n", err)
		return
	}
	// 步骤2:十进制转八进制(带前缀)
	octStr := "0" + strconv.FormatInt(dec, 8)
	fmt.Printf("十六进制%s → 八进制:%s\n", hexStr, octStr) // 输出:0x1A3 → 0643
}

常见问题

Q1、字符串前缀导致转换失败?

输入字符串带前缀(如0b/0/0x)时,忘记处理导致strconv.ParseInt()报错。

解:strconv.ParseInt()base参数指定后,会自动忽略对应前缀(如base=2忽略0bbase=8忽略0base=16忽略0x),无需手动截取前缀。

Q2、整数溢出导致转换异常?

转换后的整数超出bitSize指定的范围(如将一个 32 位二进制数转成bitSize=16的整数)

解:根据实际需求选择bitSize(如不确定,直接用64,对应int64,兼容性最强);转换前可先估算目标进制的数值范围。

// 错误:二进制10000000000000000000000000000000(32位)转成bitSize=16
binStr := "10000000000000000000000000000000"
dec, err := strconv.ParseInt(binStr, 2, 16)
fmt.Println(err) // 输出:strconv.ParseInt: parsing "10000000000000000000000000000000": value out of range

Q3、字符大小写导致十六进制转换失败?

十六进制字符串包含大写字母(如0XFF),担心转换失败

解:strconv.ParseInt()支持大小写字母,无需额外处理;如果需要统一输出格式,可使用strings.ToUpper()strings.ToLower()转换

Q4、十进制转其他进制后,需要固定位数?

转换后的字符串长度不足(如需要二进制固定 8 位、十六进制固定 2 位)。

解:使用fmt.Sprintf()格式化输出,指定宽度和填充字符(通常用0填充)。

func main() {
    dec := 5 // 十进制5
    // 二进制固定8位,不足补0
    binStr := fmt.Sprintf("%08b", dec)
    fmt.Println(binStr) // 输出:00000101

    // 十六进制固定2位,不足补0
    hexStr := fmt.Sprintf("%02X", dec)
    fmt.Println(hexStr) // 输出:05
}

Q5、strconv.Atoi()strconv.ParseInt()的区别?

  • strconv.Atoi():简化版,仅支持十进制字符串转int,等价于strconv.ParseInt(s, 10, 0)bitSize=0表示根据系统架构自动选择 32 位或 64 位)。
  • strconv.ParseInt():通用版,支持任意进制(2-36 进制),可指定整数类型(bitSize),功能更强大。
  • 建议:除了简单的十进制转换,优先使用strconv.ParseInt(),兼容性更强。

总结

go实现进制之间的转换也非常简单;通过标准库就可以实现进制转换:

  1. ​strconv包​​:处理字符串与数值互转
  2. ​fmt格式化​​:快速生成进制字符串
  3. ​位运算​​:高效处理二进制位操作

如果遇到特殊场景(如自定义进制、大整数进制转换),可以留言讨论,后续会补充更进阶的实现方案!

版权声明

未经授权,禁止转载本文章。
如需转载请保留原文链接并注明出处。即视为默认获得授权。
未保留原文链接未注明出处或删除链接将视为侵权,必追究法律责任!

本文原文链接: https://fiveyoboy.com/articles/go-base-convert/

备用原文链接: https://blog.fiveyoboy.com/articles/go-base-convert/