micropython源码分析之qstr

micropython源码分析之qstr前言最近在研究 micropython 的源码编译过程 简单记录下关于 qstr 部分内容 标识符与相应对象的联系 Micropython 中有很多标识符 例如 lcd py 中出现的标识符有 import lcd init print hello 这些标识符最终都需要与某个对象或操作联系起来 那么这种联系是如何建立的呢 那就是通过 QSTR QSTR 是 uniQueSTRing 的简称 是一种字符串内存驻留方法 我们知道同一个标识符可能在源代码中出现多次 如果我们在每个出现的地方都要保留一份这个标识符的拷贝 就会

前言

最近在研究micropython的源码编译过程,简单记录下关于qstr部分内容,本篇文章基于micropython1.18版本源码,1.19版本及之后可能会略有差异。

标识符与相应对象的联系

Micropython中有很多标识符,例如lcd.py中出现的标识符有:import、lcd、init、print、“hello”。这些标识符最终都需要与某个对象或操作联系起来。那么这种联系是如何建立的呢?那就是通过QSTR。

// This file was automatically generated by makeqstrdata.py QDEF0(MP_QSTRnull, (const byte*)"\x00\x00\x00" "") QDEF0(MP_QSTR_, (const byte*)"\x05\x15\x00" "") QDEF0(MP_QSTR___dir__, (const byte*)"\x7a\x8f\x07" "__dir__") ... 

其中是一系列的宏定义,格式为:

QDEF(MP_QSTR_xxx, (const byte*)"哈希值(2字节)长度(1字节)" "对应的字符串" 

这个文件是由makeqstrdata.py生成的,该文件位于py/makeqstrdata.py,py目录下有几个python脚本用于代码预处理c代码,包括生成qstr池,注册c模组。

QSTR生成流程

  1. 首先通过py/makeqstrdefs.py查找C源码中的MP_QSTR_XXX关键字,然后提取到ports/unix/build-standard/genhdr/qstr目录下建立新文件,增加条目Q(XXX)
  2. 然后将qstr目录下若干文件整合成一个文件ports/unix/build-standard/genhdr/qstrdefs.collected.h
  3. py/makeqstrdata.py将根据ports/unix/build-standard/genhdr/qstrdefs.collected.h生成QSTR池文件unix/build-standard/genhdr/qstrdefs.generated.h

QSTR的hash生成设置

C源码中计算qstr hash的位置位于qstr.c中

// this must match the equivalent function in makeqstrdata.py mp_uint_t qstr_compute_hash(const byte *data, size_t len) { 
    // djb2 algorithm; see http://www.cse.yorku.ca/~oz/hash.html mp_uint_t hash = 5381; for (const byte *top = data + len; data < top; data++) { 
    hash = ((hash << 5) + hash) ^ (*data); // hash * 33 ^ data } hash &= Q_HASH_MASK; // Make sure that valid hash is never zero, zero means "hash not computed" if (hash == 0) { 
    hash++; } return hash; } 

hash长度设置

在qstr.c中能看到MICROPY_QSTR_BYTES_IN_HASH宏判断,该值可赋1或2,但如果不设置则通过其他方式确定,在py/mpconfig.h文件中通过设置MICROPY_CONFIG_ROM_LEVEL来控制hash 长度是1 还是2,参见

// Number of bytes used to store qstr hash #ifndef MICROPY_QSTR_BYTES_IN_HASH #if MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES #define MICROPY_QSTR_BYTES_IN_HASH (2) #else #define MICROPY_QSTR_BYTES_IN_HASH (1) #endif #endif 

MICROPY_QSTR_BYTES_IN_HASH未被定义时参考MICROPY_CONFIG_ROM_LEVEL的设置,micropython给目标机划分了6个级别,用于适应不同硬件资源的编译。

 // Disable all optional features (i.e. minimal port). #define MICROPY_CONFIG_ROM_LEVEL_MINIMUM (0) // Only enable core features (constrained flash, e.g. STM32L072) #define MICROPY_CONFIG_ROM_LEVEL_CORE_FEATURES (10) // Enable most common features (small on-device flash, e.g. STM32F411) #define MICROPY_CONFIG_ROM_LEVEL_BASIC_FEATURES (20) // Enable convenience features (medium on-device flash, e.g. STM32F405) #define MICROPY_CONFIG_ROM_LEVEL_EXTRA_FEATURES (30) // Enable all common features (large/external flash, rp2, unix) #define MICROPY_CONFIG_ROM_LEVEL_FULL_FEATURES (40) // Enable everything (e.g. coverage) #define MICROPY_CONFIG_ROM_LEVEL_EVERYTHING (50) // Ports/boards should set this, but default to level=core. #ifndef MICROPY_CONFIG_ROM_LEVEL #define MICROPY_CONFIG_ROM_LEVEL (MICROPY_CONFIG_ROM_LEVEL_CORE_FEATURES) #endif // Helper macros for "have at least this level". #define MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES (MICROPY_CONFIG_ROM_LEVEL >= MICROPY_CONFIG_ROM_LEVEL_CORE_FEATURES) #define MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_BASIC_FEATURES (MICROPY_CONFIG_ROM_LEVEL >= MICROPY_CONFIG_ROM_LEVEL_BASIC_FEATURES) #define MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES (MICROPY_CONFIG_ROM_LEVEL >= MICROPY_CONFIG_ROM_LEVEL_EXTRA_FEATURES) #define MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_FULL_FEATURES (MICROPY_CONFIG_ROM_LEVEL >= MICROPY_CONFIG_ROM_LEVEL_FULL_FEATURES) #define MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EVERYTHING (MICROPY_CONFIG_ROM_LEVEL >= MICROPY_CONFIG_ROM_LEVEL_EVERYTHING) 

由此可以得知,MICROPY_CONFIG_ROM_LEVEL决定的hash长度,在6个级别中除了MINIMUM长度为1外其他都为2。

对象字符串长度字段的字节长度

前面我们分析过qstr宏定义的组成

QDEF(MP_QSTR_xxx, (const byte*)"哈希值(2字节)长度(1字节)" "对应的字符串" 
// Number of bytes used to store qstr length // Dictates hard limit on maximum Python identifier length, but 1 byte // (limit of 255 bytes in an identifier) should be enough for everyone #ifndef MICROPY_QSTR_BYTES_IN_LEN #define MICROPY_QSTR_BYTES_IN_LEN (1) #endif 

这样我们可以在mpconfigport.h中添加MICROPY_QSTR_BYTES_IN_LEN宏的设置就可以更改字节位长度。不过一般来说不会有超过256长度函数名,所以一般不用设置该项,只需留意有这个配置就行。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/200117.html原文链接:https://javaforall.net

(0)
上一篇 2026年3月20日 上午11:29
下一篇 2026年3月20日 上午11:30


相关推荐

  • pycharm如何同时编辑多行

    pycharm如何同时编辑多行实现像这个样子 ctrl 双击不松手 上下键 可以在同一列增加光标 ctrl shift alt 点击鼠标左键 可以在任意位置增加光标 设置好光标后就可以松开按键使用 shift ctrl 左右按键组合 可以选中光标后面的代码 进行多行编辑

    2026年3月18日
    1
  • 下载安装Java教程

    下载安装Java教程初学Java,似乎安装有那么一点不同(也就多了添加环境变量哈哈哈),我也小小记录一下。    自我介绍:win10x641.下载Java  用于现在大多数使用者用的是java8,小白的我先安装java8好了,^w^。  下载地址:Java8|JavaSE  打开网址后,选择相应电脑操作系统的版本下载。2.安装Java  2.1双击安装包开始安装  2.2安装JDK,可选择安装路径。    这个JDK其实是有包含JRE的。…

    2022年7月8日
    24
  • goland2021.11.4 激活【中文破解版】「建议收藏」

    (goland2021.11.4 激活)最近有小伙伴私信我,问我这边有没有免费的intellijIdea的激活码,然后我将全栈君台教程分享给他了。激活成功之后他一直表示感谢,哈哈~IntelliJ2021最新激活注册码,破解教程可免费永久激活,亲测有效,下面是详细链接哦~https://javaforall.net/100143.html…

    2022年3月29日
    43
  • 2020最新版Net加壳工具

    2020最新版Net加壳工具VirboxProtector发布最新版本Net加壳工具:VirboxProtector2.VirboxProtector为.NETFramework编写的软件做代码保护,防止代码被反编译,防止IL代码在内存被Dump。同时可配合授权产品实现软件的许可管理。加密技术VirboxProtector.NET版通过多种保护方式来防止反编译,加密后可让任何现有工具都无法反编译。JIT加密将.NET所有方法的IL指令经过加密,仅在.NET虚拟机进行J.

    2022年6月27日
    83
  • 虚拟机中安装windows10详细教程_openeuler虚拟机安装

    虚拟机中安装windows10详细教程_openeuler虚拟机安装Neokylin操作系统安装一、准备工作1.安装VmwareWorkstation2.下载镜像二、创建虚拟机及配置1.创建系统2.硬件配置三、选择镜像并安装系统1.导入镜像文件2.安装Neokylin操作系统一、准备工作1.安装VmwareWorkstationVMwareWorkstation是一款功能强大的桌面虚拟计算机软件,为用户提供了在单一的桌面上同时运行不同操作系统的解决方案。后续我们将通过它来创建虚拟机并安装Neokylin操作系统。下载安装包后根据提示即可快速完成安装2.下载

    2022年8月10日
    12
  • SQL SERVER与C#中数据类型的对应关系

    对应关系表SQLServer2000 http://hovertree.com/menu/sqlserver/C#CodeSmith数据类型取值范围数据类型取值范围空值代

    2021年12月27日
    36

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号