VB/VBA内置函数之Len/LenB函数(进阶版)

VB/VBA内置函数之Len/LenB函数(进阶版) 图片[1]-VB/VBA内置函数之Len/LenB函数(进阶版)-一鸣资源网

在这个红框中,题目中的这两函数值得一看

前言

正如《VB/VBA字符串》中所说,字符串在人机交互中,举足轻重,是站人这一边的,其作用甚至比变量和函数更突出。要想将VB中的字符串搞清楚,本身就涉及到变量、指针,指针的指针、数组等内容。所以要想提高字符串的处理效率,得有一个抽丝剥茧的过程,不是三言两语就能交代清楚的。

在探索VB/VBA字符串效率的过程中,除了在前文《VB/VBA/VB中哪些字符串函数 $能提高性能?》介绍的$修饰符外,还有两个大家司空见惯的函数值得一说,这便是Len和LenB函数。

图片[2]-VB/VBA内置函数之Len/LenB函数(进阶版)-一鸣资源网

字符串,至少有这么些个内容

一、判断字符串的长度

判断字符串长度,这可能是这两哥们最常去的地方。当然,字符串长度,因为编码的问题(这个有点重,后面再讲),出现了字符长度和字节长度。那Len就是获取字符串的字符长度,LenB就是获取字节长度。

1、LenB与Len之间关系

很多人觉得是这样的:2*Len=LenB。没错,在这两个函数的实现上,的确也是这么个关系。但是,直接将其视为不变的逻辑,进行套用,就会掉坑里。这就像Str=””,并非判断字符串为空的最佳方式一样(详见《VB/VBA判断字符串为空,这样更高效!》),如果不了解背后的逻辑,就很难理解。

默认情况下,也就是在VB/VBA的IDE中,只能直接输入Unicode的字符串(一个字符占2字节),所以前述关系是正确的。但,这不代表着,任何时候都正确。如果转换了编码,如将Unicode转换为ANSI,则Len函数返回的结果就是错误的(如下所示)。

如何理解更合适呢?Len函数对于字符串而言,获取Unicode编码的字符串字符大小,或许更为妥当。

2、Len和LenB的性能

控制和处理字符串的过程中,大小总是关键,毕竟绝大部分人处理字符串的过程中,都有根据大小进行遍历的经历。比如,数下一串英文中有多少个大写字符,估计除了Mid函数逐字符遍历,或赋值给字节数组后再逐元素遍历外,能用其他方法的人就很少了(有懂的,在BtOfficer看来,可能达到了VB/VBA应用的中级水平)。

这两函数,虽然极少会被高频调用,但探究其实现过程,了解下VB/VBA的编译/解释器的优化,总归还是有用的,哪怕看个放心呢。正好,BtOfficer在扩展VB/VBA的运行时(欢迎关注),可以将这两函数底层的东西,简单地说一说。

这两函数都经过了4层封装,才达到真正的实现代码。最核心的代码是什么呢?就两句:

1、『mov eax, dword ptr [eax-4]』,这句两个都有,就是从BSTR结构中取出第1个成员的值,这个在前面的链接《VB/VBA的字符串》中,有详细介绍,可前去查看。

2、『shr eax, 1』,这句只有Len有,就是将BSTR的大小,右移1位,相当于除2。所以Len=Lenb/2,就是这么来的。

BtOfficer舍弃了这两函数4层封装中的其他代码,就留了上面的核心代码,构建了StrSize函数(与LenB对应),来看下测试效果:

从测试过程可以看出,尽管Lenb函数有4层调用,但在解释器(测试是在IDE环境)的优化下,仍然比指令更少(3条指令,与Lenb的核心指令一样)的StrSize函数表现的更好。这是为什么呢?因为,此处的扩展函数StrSize的指令数,仅是函数内的指令,而没有考虑参数传递过程中的指令。如此一来,反而是优化后的Lenb代码量更少,因而更快。

因为编译器和解释器,均有相应的版权,进行修改扩展,没有合法性。所以,BtOfficer在扩展时不能使用全局优化上的便利,仅能在扩展部分进行局部优化。因此通过第三方合法扩展,要想超越Delphi,估计还是很难,顶多八八九九吧。不过从中也可以看出,VB/VBA编译器和解释器的优化性能,还是值得信耐的,只要使用得当,VB/VBA的代码性能不会差到哪儿去。

这里呢,Len/Lenb的性能是没什么问题的,哪怕是高频调用,大家也尽可放心使用。

二、判断结构体大小

在VB/VBA的通常应用中,结构体是比较少用的概念,但在复杂的API或高级应用中,结构体总是如影随形。获取结构体的尺寸,便是使用结构体的基础操作。Len和LenB函数,除了在字符串的一亩三分地里是常客,在其他方面也是不可或缺的重量级函数。

对于结构体(也即自定义类型),Len函数获得各成员的尺寸之和,而Lenb获得其占用内存大小。来看个示例:

从示例可以看出,结构体个成员大小之和与其占用内存并不一致,因为这里面涉及到对齐问题。正如《VB中Byte、Bool和Int与Lng的开销及性能相同吗?》所说,计算机里只有整齐才会更快,所以对齐的要求处处都有,VB/VBA要想提高性能,也得遵守这样的规律。

结构体涉及到的东西也比较多,后续会专题讲解,欢迎继续关注。

三、判断变量尺寸

什么是变量尺寸呢?比如Byte类型占用1字节,Boolean和Integer占用2字节,Long占用4字节等,这就是变量尺寸。如果不使用指针,那么考虑变量尺寸的场景就会很少。

当Len/Lenb的参数不是字符串常量或变量,而是其他变量名时,这两函数就可以丈量指定变量占用的内存大小,此时二者是相同的。特别指出的是,变量指向Null时,返回值也是NULL.

图片[3]-VB/VBA内置函数之Len/LenB函数(进阶版)-一鸣资源网

还可以丈量变量尺寸,有点意思

但正如《VB的任性,从Variant开始》所说,VB/VBA要考虑计算机专业素质较差的文科背景人士使用,因此不得不提供高容错特性,并尽可能隐藏专业特性。这其中,Variant功不可没。无论是VB/VBA自身内置函数的参数、返回值,还是很多系统级API,都在广泛使用这一类型。

正是这一类型在VB/VBA中的广泛使用,造就了VB/VBA的低门槛(工具意义上的灵活性,而非编程控制上的灵活性),同时也导致了让人诟病的低效性(Delphi当年紧抓不放的把柄)。所以,VB/VBA要想提高性能,更高效处理Variant才是出路(弃而不用并不经济,这与通常建议避免使用Variant,可是大相径庭的哦)。

Variant的后续内容,会逐步结合指针(注意,VB/VBA的指针,并不是调用CopyMemory函数)进行介绍,欢迎继续关注。这里结合本篇主题,讲下Len/Lenb的作用。我们知道,Variant是个容器,可以带来灵活性,但除了知道其包含的具体类型,还得知道这些类型数据的尺寸。这几乎是VB/VBA高阶应用中,最为基础的操作。

从该例可以看出,对于Variant,似乎和前面的说法不同。的确如此,当变量类型为Variant类型时,Len/Lenb会将其转换为String类型,视为String类型的值,加以判断。此时,和字符串参数是一样的。这样的特性,在VB/VBA中还有大量存在。

欢迎关注BtOfficer(收藏、点赞、关注 转发),更多精彩仍在继续哦(专栏文章将更系统,更全面),有严肃而枯燥的技术,也有轻松的唠嗑,更有现成工具等你来拿,期待你的加入!

© 版权声明
THE END