惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

The Hacker News
The Hacker News
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
P
Privacy & Cybersecurity Law Blog
C
Cybersecurity and Infrastructure Security Agency CISA
Simon Willison's Weblog
Simon Willison's Weblog
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
TaoSecurity Blog
TaoSecurity Blog
C
CERT Recently Published Vulnerability Notes
S
Security @ Cisco Blogs
Google DeepMind News
Google DeepMind News
Security Archives - TechRepublic
Security Archives - TechRepublic
T
Tenable Blog
O
OpenAI News
NISL@THU
NISL@THU
AI
AI
T
Threat Research - Cisco Blogs
Know Your Adversary
Know Your Adversary
V
Vulnerabilities – Threatpost
Schneier on Security
Schneier on Security
W
WeLiveSecurity
P
Privacy International News Feed
Cisco Talos Blog
Cisco Talos Blog
S
Secure Thoughts
D
Docker
博客园 - 三生石上(FineUI控件)
T
Troy Hunt's Blog
T
Threatpost
C
Cyber Attacks, Cyber Crime and Cyber Security
Vercel News
Vercel News
H
Hacker News: Front Page
B
Blog
S
SegmentFault 最新的问题
H
Heimdal Security Blog
T
The Blog of Author Tim Ferriss
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
G
GRAHAM CLULEY
AWS News Blog
AWS News Blog
N
News and Events Feed by Topic
L
LINUX DO - 热门话题
小众软件
小众软件
爱范儿
爱范儿
T
The Exploit Database - CXSecurity.com
Hacker News: Ask HN
Hacker News: Ask HN
Recent Announcements
Recent Announcements
Recent Commits to openclaw:main
Recent Commits to openclaw:main
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
PCI Perspectives
PCI Perspectives
I
Intezer
云风的 BLOG
云风的 BLOG
P
Proofpoint News Feed

蛮荆

如何获取更多的免费服务器 Kubernetes 调度器队列 - 设计与实现 Kubernetes 调度器 - 核心流程 Kubernetes Networking Model & CNI Kubernetes 控制器管理总结 Kubernetes CronJob 设计与实现 Kubernetes Job 设计与实现 Kubernetes HPA 设计与实现 Kubernetes Deployment 滚动更新实现原理 Kubernetes GC 设计与实现 Kubernetes Pod 驱逐 - 设计与实现 Kubernetes Daemonset 设计与实现 Kubernetes ReplicaSet 设计与实现 Kubernetes EndPoint 设计与实现 Kubernetes Informer 设计与实现 降本增效之应用优化 (三) 日志存储与检索 Kubernetes Pod 设计与实现 - 创建流程 Kubernetes 探针设计与实现 Unix 编程艺术名句摘录 Kubernetes - CRI 概述 Golang 编译速度为什么这么快? Kubernetes Pod 设计与实现 - Pause 容器 Kubernetes - kube-proxy 代理模式工程优化 Kubernetes 应用最佳实践 - 优雅关闭长连接 Kubernetes Service 类型和会话亲和性 Kubernetes 为什么需要 Ingress Kubernetes 架构 - 控制平面和数据平面 降本增效之应用优化 (二) 大报表 Go 语言如何获取 CPU 利用率 降本增效之应用优化 (一) Redis 业务规则引擎演变过程简述 微服务中的熔断算法 漏桶算法和令牌桶算法 jsonparser 为什么比标准库的 encoding/json 快 10 倍 ? zap 高性能设计与实现 HTTP Router 算法演进 fastcache 高性能设计与实现 Web 常见的三个安全问题 ants Code Reading Go 线程安全 map 方案选型 布隆过滤器 死锁、活锁、饥饿、自旋锁 sync.Pool Code Reading Go 内存管理概述 Go netpoll Code Reading goroutine 泄漏与检测 time/Timer Code Reading GMP Scheduler Code Reading Go channel 的 15 条规则和底层实现 为什么 Linux “一切皆文件” context.Context Code Reading runtime/HACKING.md Goland 最佳实践 互联网开发与金庸武学 为什么 Redis 6.0 引入多线程模型? Kubernetes 应用最佳实践 - 金丝雀发布 容器中如何正确配置 GOMAXPROCS ? singleflight Code Reading sync.Map Code Reading sync.Cond Code Reading sync.WaitGroup Code Reading sync.RWMutex Code Reading sync.Mutex Code Reading sync.Once Code Reading Go 无锁编程 sync/atomic Code Reading goroutine 交替打印奇偶数 GODEBUG Go 并发模式 Go 汇编 UUID 通用技术选型 Kubernetes 应用最佳实践 - 水平自动伸缩 Go 高性能 Tips fasthttp 为什么比标准库 net/http 快 10 倍 ? 技术文章配图指南 ChatGPT 初体验 Docker 网络原理概览 iptables 的五表五链 Kubernetes 应用最佳实践 - 亲和性和污点容忍度 Go 的反射与三大定律 Docker 官方提供的最佳实践 Go 语言内置的设计模式 HTTP1 到 HTTP3 的工程优化 Kubernetes 应用最佳实践 - Sidecar 模式 Kubernetes 应用最佳实践 - init 容器和钩子函数 为什么 recover 必须在 defer 中调用? 为什么 defer 的执行顺序和注册顺序不同? Go map 设计与实现 Go 切片扩容底层实现 Go 语言中的零拷贝 Go Delve 云原生和边缘计算简介 Kubernetes Pod 服务质量等级 Kubernetes 应用最佳实践 - 探针 Kubernetes 应用最佳实践 - 资源请求和限制 CDN 原理 Kubernetes 应用最佳实践 - 开篇 缓存策略和模式 Go 内存模型 Kubernetes 核心概念
字节序概述
2023-02-20 · via 蛮荆

字节序概述

2023-02-20 计算机基础

字节序

字节序: 多字节数据在内存中的排列顺序。

大端序和小端序

大端序: 高位字节在左边,低位字节在右边

// a = 0x12345678
// 大端序表示,符合人类阅读习惯
// -----------------------------
// | 0x12 | 0x34 | 0x56 | 0x78 |
// -----------------------------
// 低地址 <---------------> 高地址

小端序: 低位字节在左边,高位字节在右边

在计算机内部,小端序 被广泛应用于现代性 CPU 内部存储数据。

// a = 0x12345678
// 小端序表示
// -----------------------------
// | 0x78 | 0x56 | 0x34 | 0x12 |
// -----------------------------
// 低地址 <---------------> 高地址

大端序优势

检查正负位

// a = 123456
// 
//           -------------------------
// 小端序表示  | 5 | 4 | 3 | 2 | 1 | - |
//           -------------------------
//           -------------------------
// 大端序表示  | - | 1 | 2 | 3 | 4 | 5 |
//           -------------------------
//           低地址 <------------> 高地址

大端序 只需要读取第 1 位,就可以确定正负,大端序 需要读取到最后 1 位,才可以确定正负。

小端序优势

检查奇偶性

// a = 123456
// 
//           -------------------------
// 小端序表示  | 6 | 5 | 4 | 3 | 2 | 1 |
//           -------------------------
//           -------------------------
// 大端序表示  | 1 | 2 | 3 | 4 | 5 | 6 |
//           -------------------------
//           低地址 <------------> 高地址

小端序 只需要读取第 1 位,就可以确定奇偶,大端序 需要读取到最后 1 位,才可以确定奇偶。

比较大小

比较 3 个数字的大小: 1, 234, 56789

// 小端序表示
// ---------------------
// | 9 | 8 | 7 | 6 | 5 |
// | 4 | 3 | 2 |   |   |
// | 1 |   |   |   |   |
// ---------------------
// 低地址 <--------> 高地址

// 大端序表示
// ---------------------
// | 5 | 6 | 7 | 8 | 9 |
// |   |   | 2 | 3 | 4 |
// |   |   |   |   | 1 |
// ---------------------
// 低地址 <--------> 高地址

小端序 只需要从左到右读取,哪个数字读取不到下一位,就可以确定是最小的数字,大端序 需要读取到最后 1 位,才可以确定最小数字。 小端序 在极端情况下 (所有数字位数相同),和大端序一样,需要读取到最后 1 位。

乘法

计算 24165 * 3841

大端乘法

上图是 大端序 的 24165 乘以 3841,大端序 的乘法是向左进位,也就是向左边扩展,必须等到每一轮的结果都出来(上例是四轮),再相加统一写入内存。

小端乘法

上图是 小端序 的 24165 乘以 3841,小端序 的乘法是向右进位,也就是向右边扩展,左边的边界不变。每一轮结果写入内存后,就不需要移动,后面有变化只需要改动对应的位就行了。

任意精度整数

任意精度整数又称 大整数,可以存放任意大小的整数。它的内部实现是把整数分成一个个较小的单位,通常是 uint32(无符号32位整数)或 uint64(无符号64位整数),按顺序组合在一起。

// 大整数内部表示
// -------------------------------------
// | uint64 | uint64 | uint64 | uint64 |
// -------------------------------------

大端序 表示的情况下,第一个 uint64 就是这个整数最大的部分,运算时,一旦这个数发生变化,需要进位,后面的所有位都必须移动和改写。

小端序 表示的情况下,发生进位时,不需要所有位移动,所以比 大端序 更快。

小端序 的另一个好处是,如果逐字节的运算从个位数开始(比如乘法和加法),可以从左到右依次运算一个个 uint64,算完上一个再读取下一个。 大端序 就不行,必须读取整个数以后再进行运算。

更改数据类型

C 语言有一种 cast 操作,可以强制改变变量的数据类型,比如把 32 位整数强行改变为 16 位整数。

更改数据类型

上图中,32 位整数 0x00000001 更改为 16 位整数 0x0001大端序 是截去前面两个字节,这时指向这个地址的指针必须向后移动两个字节。

小端序 就没有这个问题,截去的是后面两个字节,第一位的地址是不变的,所以指针不需要移动。

总结

如果需要逐位运算,或者需要到从个位数开始运算,都是 小端序 占优势。反之,如果运算只涉及到高位,或者数据的可读性比较重要,则是 大端序 占优势。

转载声明

本文转载自 字节序探析:大端与小端的比较,笔者在文字描述和图片排版上略作修改。

补充

Go 语言标准库中的 encoding/binary 包实现了数字和字节序列之间的简单转换以及编码解码。

package binary

// Read 将结构化二进制数据读取到 data
func Read(r io.Reader, order ByteOrder, data any) error {}

// Write 将结构化二进制数据写入到 w
func Write(w io.Writer, order ByteOrder, data any) error {}

...

Read 示例代码

package main

import (
	"bytes"
	"encoding/binary"
	"fmt"
)

func main() {
	var pi float64
	b := []byte{0x18, 0x2d, 0x44, 0x54, 0xfb, 0x21, 0x09, 0x40}
	buf := bytes.NewReader(b)
	err := binary.Read(buf, binary.LittleEndian, &pi)
	if err != nil {
		fmt.Println("binary.Read failed:", err)
	}
	fmt.Println(pi)
}

// $ go run main.go
// 3.141592653589793

Write 示例代码

package main

import (
	"bytes"
	"encoding/binary"
	"fmt"
	"math"
)

func main() {
	buf := new(bytes.Buffer)
	var pi = math.Pi
	err := binary.Write(buf, binary.LittleEndian, pi)
	if err != nil {
		fmt.Println("binary.Write failed:", err)
	}
	fmt.Printf("% x\n", buf.Bytes())
}

// $ go run main.go
// 18 2d 44 54 fb 21 09 40

扩展阅读