![aea64d46377e38386b19ec8985813be6.png](https://img-blog.csdnimg.cn/img_convert/aea64d46377e38386b19ec8985813be6.png)
Lua字符串
*注*:
- 本文根据
修改而成,原文参考Lua版本为5.1.4,本文参考Lua版本为5.3.5
- 本文 Github 地址:
上一章:[Lua虚拟机解析系列]01 Lua中的数据类型,传送门
0. 概述
C 语言并没有自带处理字符串类型的库,然而对于一门编程语言来说,字符串的处理又是基础中的基础,因此,Lua 自己实现了一套处理字符串的逻辑
一般来说,要表示一个字符串,核心就是要表示一下两个数据:
- 字符串的长度
- 指向存放字符串内存数据的指针
那么,我们先来看一下 Lua 是如何表示一个字符串
1. Lua 字符串数据结构定义
首先我们来看 Lua 中表示字符串的数据结构定义:
/* (lobject.h) */
/*
** Header for string value; string bytes follow the end of this structure
** (aligned according to 'UTString'; see next).
*/
typedef struct TString {
CommonHeader;
lu_byte extra; /* reserved words for short strings; "has hash" for longs */
lu_byte shrlen; /* length for short strings */
unsigned int hash;
union {
size_t lnglen; /* length for long strings */
struct TString *hnext; /* linked list for hash table */
} u;
} TString;
/*
** Ensures that address after this type is always fully aligned.
*/
typedef union UTString {
L_Umaxalign dummy; /* ensures maximum alignment for strings */
TString tsv;
} UTString;
可以看见,Lua 这里有两个结构:
TString
:
其中字段基本都有注释,也比较容易理解
CommonHeader
:gc 对象通用部分extra
:对于短字符串来说为表示保留字,对长字符串 来说表示是否计算过 hashshrlen
:表示短字符串的长度,对长字符串无意义hash
:表示该字符串的 hash 值,如果是短字符串,则该值在创建时就计算好,因为短字符串会被添加到全局的字符串表中,避免重复创建;而对于长字符串,该值并不会立即计算,而是在需要它的时候再进行计算,计算函数为luaS_hashlongstr (TString *ts) // lstring.c
, 一旦计算过,便会将上面提到的extra
字段设置为1,避免重复计算union { lnglen; hnext; }
:对于短字符串来说,lnglen
没有意义,由于该串将被加入到全局的字符串表中,因此hnext
表示表中下一个串;对于长字符串来说,hnext
没有意义,lnglen
表示长字符串的长度,这里长字符串和短字符串之所以没有用同一个字段来表示,是因为长字符串长度可能非常长,然后短字符串最长为40
2. UTString
可以看见是一个 union,其目的是为了让TString
数据类型 按照L_Umaxalign
类型来进行对齐
/* type to ensure maximum alignment */
if defined(LUAI_USER_ALIGNMENT_T)
typedef LUAI_USER_ALIGNMENT_T L_Umaxalign;
else
typedef union {
lua_Number n;
double u;
void *s;
lua_Integer i;
long l;
} L_Umaxalign;
endif
C 语言中,struct/union 这样的复合数据类型,是按照这个类型中最大对齐量的数据来进行对齐的,而在结构体UTString
中,其最大的对齐单位肯定不会比 double 大,所以整个UTString
union 是按照 double 的对齐量来进行对齐的。
可以从UTString
的注释中得知,这样设计的目的是为了保证后面紧跟着的