深入了解 Solidity bytes

你是否知道大端小端的概念,其定义了是高位数据先保存还是地位数据先保存,EVM 是用 大端格式存储数据,我们知道 EVM 使用 32 字节的字来处理数据,当数据不足 32 个字节时,如何填充数据呢?bytes 有哪些操作详见本文。

无论是使用固定大小的bytesN还是动态大小的bytes数组,bytes 都是Solidity的一个重要方面。我们将在本文中了解它们的区别、与固定大小数组 bytesN 相关的位操作,并使用它们执行一些通用方法,如连接。

1. Solidity中的字节数据布局

关于端(Endianness )

在计算机中,术语 "端"(endianness)用来说明数据的低位字节的存储和排序方式。因此,它定义了计算机或机器存储的内部排序。

我们所说的多字节数据类型数据是指类型(如 uint、float、string等......),在计算机中,多字节数据类型有两种排序方式:小端格式或大端格式(其中格式=顺序)。

  • 大端格式下,多字节数据类型二进制表示的第一个字节先存储(高位字节先保存)。

  • 使用小端格式时,先存储多字节数据类型二进制表示的最后一个字节。(英特尔 x86 计算机)

    如:值为 0x01234567(十六进制表示法)的变量,在两个格式下的存储是这样的:

大端与小端存储 0x01234567

<p align="center">两种格式下的存储方式</p>

Solidity 中的字节数据布局

以太坊和 EVM 是一种使用 大端格式 的虚拟机。在 EVM 中,所有数据(无论其 Solidity 类型如何)都以大端格式存储在虚拟机内部。最重要的是,EVM 使用 32 字节的字来处理数据。

然而,根据其类型(bytesNuintNaddress等......),数据的布局有所不同。数据如何布局指的是高阶位数据如何放置。

在以太坊和 Solidity 开发者社区中,这被称为填充规则:左填充与右填充。

以下是Solidity中使用的填充规则:

  • 使用右填充(right-padded)类型: string, bytesbytesN.
  • 使用左填充(left-padded)类型:intN / uintN (有符号/无符号整数)、 address 和其他类型。

注意:你还会发现 "左对齐"或 "右对齐 "的说法。

为了更好地澄清和避免混淆:

左填充 = 右对齐

右填充 = 左对齐

例如,Solidity 中的 string value = "abcd" 字符串将被 EVM 填充为一个完整的 32 字节, 0 填充在右侧。

0x6162636400000000000000000000000000000000000000000000000000000000

相反,Solidity 中的数字 uint256 value = 1_633_837_924(= 0x61626364 十六进制)被 EVM 填充为一个完整的 32 字节时。0 将被填充在左边:

0x0000000000000000000000000000000000000000000000000000000061626364

学习数据布局和填充规则对于了解如何在 Solidity 中处理不同的数据类型非常重要。尤其是在处理 bytesN 和它们的 uintN 相关类型时。例如,对于 bytes1uint8 值,即使它们具有相同的位大小,其内部表示也是不同的。请看下面的代码片段。

// 0x00000000…01
Uint8 a = 1;

// 0x01000000….
byte b = 1;
bytes1 c = 

本文主要讨论 bytesNbytes 类型。Solidity 提供了两种字节类型:

  • 固定大小的字节数组:bytesN
  • 动态大小的字节数组: bytes,表示字节序列。

2. 固定大小的字节数组

可以使用关键字 bytesX 来定义变量,其中 X 代表字节数。X 可以从 1 到 32

bytebytes1 的别名,因此存储的是单字节。

如果可以将长度限制在一定的字节数,请务必使用 bytes1 至 bytes32 中的一个,因为它们更便宜。

具有固定大小变量的字节可以在合约之间传递。

3. 动态调整字节数组大小

这是一种非常特殊的类型。基本上,bytesstring是特殊的数组(参见 Solidity 文档)

bytes

bytes 来表示任意长度的原始字节数据

在 Solidity 中,术语 bytes 表示字节动态数组。它是 byte[] 的简写。

在 Solidity 代码中,bytes被视为数组,因此它的长度可以为零,你也可以在它的末尾添加一个字节。

然而,bytes并不是一个值类型!

string

若是任意长度的字符串(UTF-8)数据使用字符串。

bytes32 someString = "stringliteral";

该字符串常量量分配给 bytes32 类型时,将以原始字节形式解释。

但是,字符串不能在合约之间传递,因为它们不是固定大小的变量。

Solidity 本身没有字符串操作函数(除了 concat),但第三方字符串库可以使用。

4. Solidity 中的位运算

本节大部分内容基于以下作者的文章Maksym

Solidity 支持基本的位操作(虽然缺少一些,如左移右移),幸好有算术相等。下面将介绍一些位操作的基本原理。

比较运算符

以下用于字节的比较运算符的值为 bool 值: truefalse

&lt;=, &lt;, ==, !=, >=, >

位运算符

Solidity 中提供了以下位运算符: & (与), | (或), ^ (异或)~ (非).

为简单起见,我们将对两个变量使用 bytes1 数据类型(等于 byte ):ab。我们将在 Solidity 中使用它们的十六进制表示法来初始化它们。

bytes1 a = 0xb5; //  [10110101]
bytes1 b = 0x56; //  [01010110]

下表显示了它们的二进制格式。

img

注: 输入为白色背景,结果将以黄色高亮显示

让我们来看看 :


& () : 两个位都必须是 1(白色行),结果才为 true(1 => 黄色行)。

img

a & b; // Result: 0x14  [00010100]

| () : 至少...

剩余50%的内容订阅专栏后可查看

点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
翻译小组
翻译小组
0x9e64...7c84
大家看到好的文章可以在 GitHub 提 Issue: https://github.com/lbc-team/Pioneer/issues 欢迎关注我的 Twitter: https://twitter.com/UpchainDAO