<!--[endif]-->
C++中字母大小写转换实现的优化
write by 九天雁翎(JTianLing) --
blog.csdn.net/vagrxie
讨论新闻组及文件
在本文中全部以转换为小写为例。
从推荐复用代码的角度来看,用库函数是不错的办法:
方案一:
char gc1[53] = "abcdefghigklmnopqrstuvwxyzABCDEFGHIGKLMNOPQRSTUVWXYZ";
void wayOne()
{
strlwr(gc1);
}
优点是使用方便,别人看着也容易理解,但是效率慢的让人吐血。
extern "C" char * __cdecl _strlwr (
char * string
)
{
if (__locale_changed == 0)
{
char * cp;
/* validation
section */
_VALIDATE_RETURN(string != NULL,
EINVAL, NULL);
for (cp=string; *cp; ++cp)
{
if
('A' <= *cp
&& *cp <= 'Z')
*cp
+= 'a' - 'A';
}
return(string);
}
else
{
_strlwr_s_l(string, (size_t)(-1),
NULL);
return string;
}
}
循环中平均2.5次的判断,(*cp一次,if的’A’<=一次,*cp<=版次)加平均每次0.5次的加法,虽然这样的转换O(n)是必不可少的,但是对于这样多的操作还是慢的可怕。
例2:
char gc2[53]
= "abcdefghigklmnopqrstuvwxyzABCDEFGHIGKLMNOPQRSTUVWXYZ";
namespace MYTEST
{
inline char*
strlwr(char
*asz)
{
for(char*
lp = gc2;
*lp != 0; ++lp)
{
*lp |= 0x20;
}
return asz;
}
}
void wayTwo()
{
MYTEST::strlwr(gc2);
}
此例中利用了ASCII字母值的特点,一共只有一次判断(*lp!=0),一次位或操作。算法上提高了很多:)其实已经达到了1/3的效率提升。。。。。
将原来一大堆的代码,转化成了反汇编只有4句的程序:
00401020 80 08 20 or byte ptr [eax],20h
00401023 83 C0 01 add eax,1
00401026 80 38 00 cmp byte ptr [eax],0
00401029 75 F5 jne wayTwo+10h (401020h)
但是考虑到char只是1个字节,看到
00401020 80 08 20 or byte ptr [eax],20h
一句都感觉不爽,白白浪费了eax 这样4个字节的寄存器,于是可以这样优化:
namespace MYTEST2
{
inline char*
strlwr(char
*asz)
{
long* lp
= (long*)gc3;
for(; *((char*)lp) != 0; ++lp)
{
(long)(*lp) |= 0x20202020;
}
for(char*
lpc = (char*)lp;*lpc!=0; ++lpc)
{
*lpc |= 0x20;
}
return asz;
}
}
说实话,。。。。。。。。。。。没有任何清晰性可言,没有任何可读性可言,但是优化的思想就是充分的利用4个字节的寄存器,并且以DWORD来读取内存,这是很有效率的方式。汇编代码其实比C语言代码更加清晰,原因在于C语言代码还需要处理大量与类型相关的事情,汇编代码不需要。
第一个循环汇编代码如下:
00401040 81 08 20 20 20 20 or dword ptr [eax],20202020h
00401046 83 C0 04 add eax,4
00401049 80 38 00 cmp byte ptr [eax],0
0040104C 75 F2 jne wayThree+10h (401040h)
将循环次数减少了3/4。。。。所以效率的优化还是很明显的。单指令多数据操作的思想不过就是这种思想的延生罢了。。。呵呵,但是说在前面,如此影响可读性的效率优化,除非在很必要的情况下,不然慎用。。。。。
为了证实效率的优化,起码也得给出一个测试结果给大家看看吧,不然还以为我胡扯了。
void wayOne()
// Hit Count : 1
// Time : 5553.00
// Time with Children : 5553.00
{
strlwr(gc1);
}
void wayTwo()
// Hit Count : 1
// Time : 247.00
// Time with Children : 247.00
{
MYTEST::strlwr(gc2);
}
void wayThree()
// Hit Count : 1
// Time : 180.00
// Time with Children : 180.00
{
MYTEST2::strlwr(gc3);
}
int _tmain(int argc, _TCHAR* argv[])
// Hit Count : 1
// Time : 6836996435.00
// Time with Children : 6837002415.00
{
wayThree();
wayTwo();
wayOne();
}
测试结果为AQtime5测试数据,单位为机器周期,因为结果已经很明显了,所以没有进行多次循环的测试。并且为了排除缓存的影响,将最快的放在了最前面,那么哪怕有缓存的影响,对于wayThree也是最不利的才对。库函数的5000多的结果,说慢的可怕并不为过。在数据量很大的时候,这种优化的差异可不是一点点而已。
write by 九天雁翎(JTianLing)
-- blog.csdn.net/vagrxie
分享到:
相关推荐
C++实现字母大小写转换
字符串大小写转换的2种方法C++,对任意输入的字符串可实现字符串大小写的转换。
C、C++实现字母/英文句子大小写转换
数据结构大小写字母转换的实验报告完整版,内容很简单,很直白。
Java下使用for循环实现转从最后一个字符开始遍历,2) 遍历的当前字符如果是大写字母,就使用toLowerCase()方法将其转换为小写字母, 如果是小写字母则使用toUpperCase() 方法将其转换为大写字母
编写一个程序,将一个包含大小写字母的纯字母明文串转换为纯大写字母的加密串输出。
字母大小写转换的代码—简单
c 大小写字母转换 示例中,我们使用了toupper()和tolower()函数来分别将字符 'a' 转换为大写和小写。你可以用这些函数来处理...注意:这些函数只会对字母字符进行大小写转换,对于非字母字符,它们不会产生任何影响。
最近工作中遇到一个需求,是需要将URL中的 query 参数的key全部转换为小写或者大写,键值对的数量有点多,但全部都是英文字母,无需考虑非字母的情况。 实现比较快的做法是使用STL或C标准库中的转换接口,如下: #...
这个算法的主要目的是交换字符串中的大写字母和小写字母。以下是算法的详细描述: 定义一个函数swapCase,它接受一个字符串引用作为参数。 遍历字符串中的每个字符。 对于每个字符,检查它是否为大写字母。如果是,...
字符串字母大小写转换 字符串大小写交互5.cpp 使用C++实现
该程序可以输入大写,转化成小写,支持两种模式即大写全部转换为小写,和保留单词的首字母大写,适合在外文文献的阅读时使用。最大长度为300个字符。
C++练习题,适合新手。...这个函数将字符串中所有单词的第一个字母转 化为大写,如果字母已经是大写则保留。让用户输入一个字符串,然后将字符串作为参数 传递给一个子函数,最后将变换后的最终结果显示在屏幕上。
写自定义函数stringLower()实现将一个字符串中所有大写字母变为小写字母。在主函数中输入一含有大写字母的字符串,调用该函数并输出改变后的字符串。
1、输入一个字符串,将该字符串中的所有小写字母转换为大写字母后输出。 2、输入一个字符串,...4、输入一个由26个英文字母(不分大小写)组成的字符串,再输入一个英文字母,查找该字母在字符串中第一次出现的位置。
用C++写的大写字母转小写的程序,适合新手完成小作业时参考
本书故意省略了 C++标准库中的某些部分 比如对本地化和算术运算库的支持 C++标 准库非常广泛 要想介绍它的所有方面 则远远超出了本书的范围 在后面所附的参考文献 中 某些书更详细地讨论了该库 见 MUSSER96 和 ...
0113 在进行字符串比较时忽略大小写 50 0114 获取字符串中的英文子字符串 51 2.5 字符串技巧 52 0115 字符串加密 52 0116 字符串连接 52 0117 如何在字符串中使用双引号 53 0118 如何在字符串中添加多...