SQLite hex 的整数参数:255 为什么变成 323535,而不是 FF
把数据库里的整数 255 交给 hex,希望得到 FF,结果却多出六个字符 323535。函数没有把整数算错,而是在处理另一种表示:数字先变成十进制文字,随后编码这些文字的字节。
下面分别传入 Python 整数、字符串和 bytes,保持查询参数绑定,避免 SQL 字面量掩盖输入类型。保存为 demo.py,再运行 python3 demo.py;只使用标准库与内存数据库,没有文件和网络操作。
AI模型生成概念示意:同一个整数分别走向文字字节和进制显示两条路径;非实测截图。
import sqlite3
db = sqlite3.connect(":memory:")
try:
numeric = db.execute("SELECT hex(?), printf('%X', ?)", (255, 255)).fetchone()
text = db.execute("SELECT hex(?)", ("255",)).fetchone()[0]
binary = db.execute("SELECT hex(?)", (bytes([255]),)).fetchone()[0]
assert numeric == ("323535", "FF")
assert text == "323535" and binary == "FF"
print("integer hex/printf:", numeric)
print("text hex:", text)
print("blob hex:", binary)
casted = db.execute("SELECT hex(CAST(? AS BLOB))", (255,)).fetchone()[0]
assert casted == "323535"
print("cast integer to blob:", casted)
payload = (255).to_bytes(2, "big")
encoded = db.execute("SELECT hex(?)", (payload,)).fetchone()[0]
assert encoded == "00FF"
assert int.from_bytes(payload, "big") == 255
print("explicit two-byte payload:", encoded)
finally:
db.close()先看输入究竟是什么
五行输出依次是 integer hex/printf: ('323535', 'FF')、text hex: 323535、blob hex: FF、cast integer to blob: 323535,以及 explicit two-byte payload: 00FF。前两行相同,因为数字 255 的文字表示也是三个字符“255”。
UTF-8 中字符 2 的字节是十六进制 32,字符 5 是 35,连接后便成为 323535。bytes([255]) 则只有一个值为 255 的字节,所以得到 FF。两者包含的信息不同,不能仅因都能打印为十六进制文字,就认为它们是同一种载荷。
想把整数按十六进制展示,可以使用 printf 的 %X;小写 %x 则使用小写字母。这属于数值格式化。hex 更适合观察已经明确为字节序列的内容,例如定位一个 BLOB 的某个字节,而不是替代数值格式转换。
显式转换类型仍要核对转换规则
第四行说明 CAST(255 AS BLOB) 也没有产生整数的机器存储布局。这里仍得到文字的字节。多套一层 CAST 只明确了结果类型,没有声明你期待的一字节、两字节、大小端或有符号编码。那些约定需要另外指定。
最后用 to_bytes(2, "big") 先构造两个字节,再绑定给 SQLite,因此得到 00FF。最前面的 00 表示约定的固定宽度,不是数据缺失。对应的 int.from_bytes 断言验证相同字节序可以取回 255;真实协议还应明确宽度、符号与允许范围。
本文选的是小型非负整数,不能据此直接推断负数或浮点数应该怎样序列化。准备写二进制报文时,应先根据协议限定数值,再生成 BLOB。若只是给人看的编号,则通常只需要格式化,不必先制造二进制载荷。
验收时保留三个看似相近的输入:整数 255、文字 255、单字节 FF,并检查数据库中的实际类型。这样能发现上游把字节误转为数字或文本的变化。也不要把 hex 当成加密或校验摘要,它只是把已有内容换一种可读表示。
资料核对日期:2026年10月2日。最终展示代码在 Python 3.12.14 / SQLite 3.53.1 独立运行并通过全部断言;结果对应文中固定输入。


