程序14-9 linux/include/string.h


  1 #ifndef _STRING_H_

  2 #define _STRING_H_

  3

  4 #ifndef NULL

  5 #define NULL ((void *) 0)

  6 #endif

  7

  8 #ifndef _SIZE_T

  9 #define _SIZE_T

 10 typedef unsigned int size_t;

 11 #endif

 12

 13 extern char * strerror(int errno);

 14

 15 /*

 16  * This string-include defines all string functions as inline

 17  * functions. Use gcc. It also assumes ds=es=data space, this should be

 18  * normal. Most of the string-functions are rather heavily hand-optimized,

 19  * see especially strtok,strstr,str[c]spn. They should work, but are not

 20  * very easy to understand. Everything is done entirely within the register

 21  * set, making the functions fast and clean. String instructions have been

 22  * used through-out, making for "slightly" unclear code :-)

 23  *

 24  *              (C) 1991 Linus Torvalds

 25  */

    /*

     * 这个字符串头文件以内嵌函数的形式定义了所有字符串操作函数。使�gcc时,同时

     * 假定�ds=es=数据空间,这应该是常规的。绝大多数字符串函数都是经手工进行大�

     * 优化的,尤其是函�strtokstrstrstr[c]spn。它们应该能正常工作,但却不是那

     * 么容易理解。所有的操作基本上都是使用寄存器集来完成的,这使得函数即快又整洁�

     * 所有地方都使用了字符串指令,这又使得代码“稍微”难以理�J

     *

     *              (C) 1991 Linus Torvalds

     */

 26 

    //// 将一个字符串(src)拷贝到另一个字符串(dest),直到遇�NULL字符后停歀�

    // 参数�dest - 目的字符串指针,src - 源字符串指针�

    // %0 - esi(src)%1 - edi(dest)

 27 extern inline char * strcpy(char * dest,const char *src)

 28 {

 29 __asm__("cld\n"                      // 清方向位�

 30         "1:\tlodsb\n\t"              // 加载DS:[esi]1字节èal,并更新esi

 31         "stosb\n\t"                  // 存储字节alèES:[edi],并更新edi

 32         "testb %%al,%%al\n\t"        // 刚存储的字节�0

 33         "jne 1b"                     // 不是则向后跳转到标号1处,否则结束�

 34         ::"S" (src),"D" (dest):"si","di","ax");

 35 return dest;                         // 返回目的字符串指针�

 36 }

 37

    //// 拷贝源字符串count个字节到目的字符串�

    // 如果源串长度小于count个字节,就附加空字符(NULL)到目的字符串�

    // 参数�dest - 目的字符串指针,src - 源字符串指针�count - 拷贝字节数�

    // %0 - esi(src)%1 - edi(dest)%2 - ecx(count)

 38 extern inline char * strncpy(char * dest,const char *src,int count)

 39 {

 40 __asm__("cld\n"                      // 清方向位�

 41         "1:\tdecl %2\n\t"            // 寄存�ecx--count--)�

 42         "js 2f\n\t"                  // 如果count<0则向前跳转到标号2,结束�

 43         "lodsb\n\t"                  // ds:[esi]1字节èal,并�esi++

 44         "stosb\n\t"                  // 存储该字�èes:[edi],并�edi++

 45         "testb %%al,%%al\n\t"        // 该字节是0

 46         "jne 1b\n\t"                 // 不是,则向前跳转到标�1处继续拷贝�

 47         "rep\n\t"                    // 否则,在目的串中存放剩余个数的空字符�

 48         "stosb\n"

 49         "2:"

 50         ::"S" (src),"D" (dest),"c" (count):"si","di","ax","cx");

 51 return dest;                         // 返回目的字符串指针�

 52 }

 53

    //// 将源字符串拷贝到目的字符串的末尾处�

    // 参数�dest - 目的字符串指针,src - 源字符串指针�

    // %0 - esi(src)%1 - edi(dest)%2 - eax(0)%3 - ecx(-1)

 54 extern inline char * strcat(char * dest,const char * src)

 55 {

 56 __asm__("cld\n\t"                    // 清方向位�

 57         "repne\n\t"                  // 比较ales:[edi]字节,并更新edi++

 58         "scasb\n\t"                  // 直到找到目的串中�0的字节,此时edi已指向后1字节�

 59         "decl %1\n"                  // es:[edi]指向0值字节�

 60         "1:\tlodsb\n\t"              // 取源字符串字�ds:[esi]èal,并esi++

 61         "stosb\n\t"                  // 将该字节存到es:[edi],并edi++

 62         "testb %%al,%%al\n\t"        // 该字节是0

 63         "jne 1b"                     // 不是,则向后跳转到标�1处继续拷贝,否则结束�

 64         ::"S" (src),"D" (dest),"a" (0),"c" (0xffffffff):"si","di","ax","cx");

 65 return dest;                         // 返回目的字符串指针�

 66 }

 67

    //// 将源字符串的count个字节复制到目的字符串的末尾处,最后添一空字符�

    // 参数�dest - 目的字符串,src - 源字符串�count - 欲复制的字节数�

    // %0 - esi(src)%1 - edi(dest)%2 - eax(0)%3 - ecx(-1)%4 - (count)

 68 extern inline char * strncat(char * dest,const char * src,int count)

 69 {

 70 __asm__("cld\n\t"                    // 清方向位�

 71         "repne\n\t"                  // 比较ales:[edi]字节�edi++

 72         "scasb\n\t"                  // 直到找到目的串的末端0值字节�

 73         "decl %1\n\t"                // edi指向�0值字节�

 74         "movl %4,%3\n"               // 欲复制字节数èecx

 75         "1:\tdecl %3\n\t"            // ecx--(从0开始计数)�

 76         "js 2f\n\t"                  // ecx <0 ?,是则向前跳转到标号2处�

 77         "lodsb\n\t"                  // 否则�ds:[esi]处的字节èalesi++

 78         "stosb\n\t"                  // 存储�es:[edi]处,edi++

 79         "testb %%al,%%al\n\t"        // 该字节值为0

 80         "jne 1b\n"                   // 不是则向后跳转到标号1处,继续复制�

 81         "2:\txorl %2,%2\n\t"         // al清零�

 82         "stosb"                      // 存到es:[edi]处�

 83         ::"S" (src),"D" (dest),"a" (0),"c" (0xffffffff),"g" (count)

 84         :"si","di","ax","cx");

 85 return dest;                         // 返回目的字符串指针�

 86 }

 87

    //// 将一个字符串与另一个字符串进行比较�

    // 参数�cs - 字符�1ct - 字符�2

    // %0 - eax(__res)返回值,%1 - edi(cs)字符�1指针�%2 - esi(ct)字符�2指针�

    // 返回:如果串1 > 2,则返回1;串1 = 2,则返回0;串1 < 2,则返回-1

    // 90行定义了一个局部寄存器变量。该变量将被保存�eax寄存器中,以便于高效访问和操作�

    // 这种定义变量的方法主要用于内嵌汇编程序中。详细说明参�gcc手册指定寄存器中的变�

 88 extern inline int strcmp(const char * cs,const char * ct)

 89 {

 90 register int __res __asm__("ax");    // __res是寄存器变量(eax)

 91 __asm__("cld\n"                      // 清方向位�

 92         "1:\tlodsb\n\t"              // 取字符串2的字�ds:[esi]èal,并�esi++

 93         "scasb\n\t"                  // al与字符串1的字�es:[edi]作比较,并且edi++

 94         "jne 2f\n\t"                 // 如果不相等,则向前跳转到标号2

 95         "testb %%al,%%al\n\t"        // 该字节是0值字节吗(字符串结尾)?

 96         "jne 1b\n\t"                 // 不是,则向后跳转到标�1,继续比较�

 97         "xorl %%eax,%%eax\n\t"       // 是,则返回�eax清零�

 98         "jmp 3f\n"                   // 向前跳转到标�3,结束�

 99         "2:\tmovl $1,%%eax\n\t"      // eax中置1

100         "jl 3f\n\t"                  // 若前面比较中�2字符<1字符,则返回正值结束�

101         "negl %%eax\n"               // 否则eax = -eax,返回负值,结束�

102         "3:"

103         :"=a" (__res):"D" (cs),"S" (ct):"si","di");

104 return __res;                        // 返回比较结果�

105 }

106

    //// 字符�1与字符串2的前count个字符进行比较�

    // 参数�cs - 字符�1ct - 字符�2count - 比较的字符数�

    // %0 - eax(__res)返回值,%1 - edi(cs)1指针�%2 - esi(ct)2指针�%3 - ecx(count)

    // 返回:如果串1 > 2,则返回1;串1 = 2,则返回0;串1 < 2,则返回-1

107 extern inline int strncmp(const char * cs,const char * ct,int count)

108 {

109 register int __res __asm__("ax");    // __res是寄存器变量(eax)

110 __asm__("cld\n"                      // 清方向位�

111         "1:\tdecl %3\n\t"            // count--

112         "js 2f\n\t"                  // 如果count<0,则向前跳转到标�2

113         "lodsb\n\t"                  // 取串2的字�ds:[esi]èal,并�esi++

114         "scasb\n\t"                  // 比较al与串1的字�es:[edi],并�edi++

115         "jne 3f\n\t"                 // 如果不相等,则向前跳转到标号3

116         "testb %%al,%%al\n\t"        // 该字符是NULL字符吗?

117         "jne 1b\n"                   // 不是,则向后跳转到标�1,继续比较�

118         "2:\txorl %%eax,%%eax\n\t"   // NULL字符,则eax清零(返回值)�

119         "jmp 4f\n"                   // 向前跳转到标�4,结束�

120         "3:\tmovl $1,%%eax\n\t"      // eax中置1

121         "jl 4f\n\t"                  // 如果前面比较中串2字符<1字符,则返回1结束�

122         "negl %%eax\n"               // 否则eax = -eax,返回负值,结束�

123         "4:"

124         :"=a" (__res):"D" (cs),"S" (ct),"c" (count):"si","di","cx");

125 return __res;                        // 返回比较结果�

126 }

127

    //// 在字符串中寻找第一个匹配的字符�

    // 参数�s - 字符串,c - 欲寻找的字符�

    // %0 - eax(__res)%1 - esi(字符串指�s)%2 - eax(字符c)

    // 返回:返回字符串中第一次出现匹配字符的指针。若没有找到匹配的字符,则返回空指针�

128 extern inline char * strchr(const char * s,char c)

129 {

130 register char * __res __asm__("ax"); // __res是寄存器变量(eax)

131 __asm__("cld\n\t"                    // 清方向位�

132         "movb %%al,%%ah\n"           // 将欲比较字符移到ah

133         "1:\tlodsb\n\t"              // 取字符串中字�ds:[esi]èal,并�esi++

134         "cmpb %%ah,%%al\n\t"         // 字符串中字符al与指定字�ah相比较�

135         "je 2f\n\t"                  // 若相等,则向前跳转到标号2处�

136         "testb %%al,%%al\n\t"        // al中字符是NULL字符吗?(字符串结尾?)

137         "jne 1b\n\t"                 // 若不是,则向后跳转到标号1,继续比较�

138         "movl $1,%1\n"               // 是,则说明没有找到匹配字符,esi1

139         "2:\tmovl %1,%0\n\t"         // 将指向匹配字符后一个字节处的指针值放�eax

140         "decl %0"                    // 将指针调整为指向匹配的字符�

141         :"=a" (__res):"S" (s),"0" (c):"si");

142 return __res;                        // 返回指针�

143 }

144

    //// 寻找字符串中指定字符最后一次出现的地方。(反向搜索字符串)

    // 参数�s - 字符串,c - 欲寻找的字符�

    // %0 - edx(__res)%1 - edx(0)%2 - esi(字符串指�s)%3 - eax(字符c)

    // 返回:返回字符串中最后一次出现匹配字符的指针。若没有找到匹配的字符,则返回空指针�

145 extern inline char * strrchr(const char * s,char c)

146 {

147 register char * __res __asm__("dx"); // __res是寄存器变量(edx)

148 __asm__("cld\n\t"                    // 清方向位�

149         "movb %%al,%%ah\n"           // 将欲寻找的字符移�ah

150         "1:\tlodsb\n\t"              // 取字符串中字�ds:[esi]èal,并�esi++

151         "cmpb %%ah,%%al\n\t"         // 字符串中字符al与指定字�ah作比较�

152         "jne 2f\n\t"                 // 若不相等,则向前跳转到标�2处�

153         "movl %%esi,%0\n\t"          // 将字符指针保存到edx中�

154         "decl %0\n"                  // 指针后退一位,指向字符串中匹配字符处�

155         "2:\ttestb %%al,%%al\n\t"    // 比较的字符是0吗(到字符串尾)�

156         "jne 1b"                     // 不是则向后跳转到标号1处,继续比较�

157         :"=d" (__res):"0" (0),"S" (s),"a" (c):"ax","si");

158 return __res;                        // 返回指针�

159 }

160

    //// 在字符串1中寻找第1个字符序列,该字符序列中的任何字符都包含在字符串2中�

    // 参数�cs - 字符�1指针�ct - 字符�2指针�

    // %0 - esi(__res)%1 - eax(0)%2 - ecx(-1)%3 - esi(1指针cs)%4 - (2指针ct)

    // 返回字符�1中包含字符串2中任何字符的首个字符序列的长度值�

161 extern inline int strspn(const char * cs, const char * ct)

162 {

163 register char * __res __asm__("si"); // __res是寄存器变量(esi)

164 __asm__("cld\n\t"                    // 清方向位�

165         "movl %4,%%edi\n\t"          // 首先计算�2的长度。串2指针放入edi中�

166         "repne\n\t"                  // 比较al(0)与串2中的字符�es:[edi]),�edi++

167         "scasb\n\t"                  // 如果不相等就继续比较(ecx逐步递减)

168         "notl %%ecx\n\t"             // ecx中每位取反�

169         "decl %%ecx\n\t"             // ecx--,得�2的长度值�

170         "movl %%ecx,%%edx\n"         // 将串2的长度值暂放入edx中�

171         "1:\tlodsb\n\t"              // 取串1字符ds:[esi]èal,并�esi++

172         "testb %%al,%%al\n\t"        // 该字符等�0值吗(串1结尾)?

173         "je 2f\n\t"                  // 如果是,则向前跳转到标号2处�

174         "movl %4,%%edi\n\t"          // 取串2头指针放�edi中�

175         "movl %%edx,%%ecx\n\t"       // 再将�2的长度值放�ecx中�

176         "repne\n\t"                  // 比较al与串2中字�es:[edi],并�edi++

177         "scasb\n\t"                  // 如果不相等就继续比较�

178         "je 1b\n"                    // 如果相等,则向后跳转到标�1处�

179         "2:\tdecl %0"                // esi--,指向最后一个包含在�2中的字符�

180         :"=S" (__res):"a" (0),"c" (0xffffffff),"0" (cs),"g" (ct)

181         :"ax","cx","dx","di");

182 return __res-cs;                     // 返回字符序列的长度值�

183 }

184

    //// 寻找字符�1中不包含字符�2中任何字符的首个字符序列�

    // 参数�cs - 字符�1指针�ct - 字符�2指针�

    // %0 - esi(__res)%1 - eax(0)%2 - ecx(-1)%3 - esi(1指针cs)%4 - (2指针ct)

    // 返回字符�1中不包含字符�2中任何字符的首个字符序列的长度值�

185 extern inline int strcspn(const char * cs, const char * ct)

186 {

187 register char * __res __asm__("si"); // __res是寄存器变量(esi)

188 __asm__("cld\n\t"                    // 清方向位�

189         "movl %4,%%edi\n\t"          // 首先计算�2的长度。串2指针放入edi中�

190         "repne\n\t"                  // 比较al(0)与串2中的字符�es:[edi]),�edi++

191         "scasb\n\t"                  // 如果不相等就继续比较(ecx逐步递减)

192         "notl %%ecx\n\t"             // ecx中每位取反�

193         "decl %%ecx\n\t"             // ecx--,得�2的长度值�

194         "movl %%ecx,%%edx\n"         // 将串2的长度值暂放入edx中�

195         "1:\tlodsb\n\t"              // 取串1字符ds:[esi]èal,并�esi++

196         "testb %%al,%%al\n\t"        // 该字符等�0值吗(串1结尾)?

197         "je 2f\n\t"                  // 如果是,则向前跳转到标号2处�

198         "movl %4,%%edi\n\t"          // 取串2头指针放�edi中�

199         "movl %%edx,%%ecx\n\t"       // 再将�2的长度值放�ecx中�

200         "repne\n\t"                  // 比较al与串2中字�es:[edi],并�edi++

201         "scasb\n\t"                  // 如果不相等就继续比较�

202         "jne 1b\n"                   // 如果不相等,则向后跳转到标号1处�

203         "2:\tdecl %0"                // esi--,指向最后一个包含在�2中的字符�

204         :"=S" (__res):"a" (0),"c" (0xffffffff),"0" (cs),"g" (ct)

205         :"ax","cx","dx","di");

206 return __res-cs;                     // 返回字符序列的长度值�

207 }

208

    //// 在字符串1中寻找首个包含在字符�2中的任何字符�

    // 参数�cs - 字符�1的指针,ct - 字符�2的指针�

    // %0 -esi(__res)%1 -eax(0)%2 -ecx(0xffffffff)%3 -esi(1指针cs)%4 -(2指针ct)

    // 返回字符�1中首个包含字符串2中字符的指针�

209 extern inline char * strpbrk(const char * cs,const char * ct)

210 {

211 register char * __res __asm__("si"); // __res是寄存器变量(esi)

212 __asm__("cld\n\t"                    // 清方向位�

213         "movl %4,%%edi\n\t"          // 首先计算�2的长度。串2指针放入edi中�

214         "repne\n\t"                  // 比较al(0)与串2中的字符�es:[edi]),�edi++

215         "scasb\n\t"                  // 如果不相等就继续比较(ecx逐步递减)

216         "notl %%ecx\n\t"             // ecx中每位取反�

217         "decl %%ecx\n\t"             // ecx--,得�2的长度值�

218         "movl %%ecx,%%edx\n"         // 将串2的长度值暂放入edx中�

219         "1:\tlodsb\n\t"              // 取串1字符ds:[esi]èal,并�esi++

220         "testb %%al,%%al\n\t"        // 该字符等�0值吗(串1结尾)?

221         "je 2f\n\t"                  // 如果是,则向前跳转到标号2处�

222         "movl %4,%%edi\n\t"          // 取串2头指针放�edi中�

223         "movl %%edx,%%ecx\n\t"       // 再将�2的长度值放�ecx中�

224         "repne\n\t"                  // 比较al与串2中字�es:[edi],并�edi++

225         "scasb\n\t"                  // 如果不相等就继续比较�

226         "jne 1b\n\t"                 // 如果不相等,则向后跳转到标号1处�

227         "decl %0\n\t"                // esi--,指向一个包含在�2中的字符�

228         "jmp 3f\n"                   // 向前跳转到标�3处�

229         "2:\txorl %0,%0\n"           // 没有找到符合条件的,将返回值为NULL

230         "3:"

231         :"=S" (__res):"a" (0),"c" (0xffffffff),"0" (cs),"g" (ct)

232         :"ax","cx","dx","di");

233 return __res;                        // 返回指针值�

234 }

235

    //// 在字符串1中寻找首个匹配整个字符串2的字符串�

    // 参数�cs - 字符�1的指针,ct - 字符�2的指针�

    // %0 -eax(__res)%1 -eax(0)%2 -ecx(0xffffffff)%3 -esi(1指针cs)%4 -(2指针ct)

    // 返回:返回字符串1中首个匹配字符串2的字符串指针�

236 extern inline char * strstr(const char * cs,const char * ct)

237 {

238 register char * __res __asm__("ax"); // __res是寄存器变量(eax)

239 __asm__("cld\n\t" \                  // 清方向位�

240         "movl %4,%%edi\n\t"          // 首先计算�2的长度。串2指针放入edi中�

241         "repne\n\t"                  // 比较al(0)与串2中的字符�es:[edi]),�edi++

242         "scasb\n\t"                  // 如果不相等就继续比较(ecx逐步递减)

243         "notl %%ecx\n\t"             // ecx中每位取反�

244         "decl %%ecx\n\t"    /* NOTE! This also sets Z if searchstring='' */

                                /* 注意!如果搜索串为空,将设置Z标志 */ // 得串2的长度值�

245         "movl %%ecx,%%edx\n"         // 将串2的长度值暂放入edx中�

246         "1:\tmovl %4,%%edi\n\t"      // 取串2头指针放�edi中�

247         "movl %%esi,%%eax\n\t"       // 将串1的指针复制到eax中�

248         "movl %%edx,%%ecx\n\t"       // 再将�2的长度值放�ecx中�

249         "repe\n\t"                   // 比较�1和串2字符(ds:[esi],es:[edi])esi++,edi++

250         "cmpsb\n\t"                  // 若对应字符相等就一直比较下去�

251         "je 2f\n\t"         /* also works for empty string, see above */

                                /* 对空串同样有效,见上� */ // 若全相等,则转到标号2

252         "xchgl %%eax,%%esi\n\t"      // 1头指�èesi,比较结果的�1指针èeax

253         "incl %%esi\n\t"             // 1头指针指向下一个字符�

254         "cmpb $0,-1(%%eax)\n\t"      // 1指针(eax-1)所指字节是0吗?

255         "jne 1b\n\t"                 // 不是则转到标�1,继续从�1的第2个字符开始比较�

256         "xorl %%eax,%%eax\n\t"       // eax,表示没有找到匹配�

257         "2:"

258         :"=a" (__res):"0" (0),"c" (0xffffffff),"S" (cs),"g" (ct)

259         :"cx","dx","di","si");

260 return __res;                        // 返回比较结果�

261 }

262

    //// 计算字符串长度�

    // 参数�s - 字符串�

    // %0 - ecx(__res)%1 - edi(字符串指�s)%2 - eax(0)%3 - ecx(0xffffffff)

    // 返回:返回字符串的长度�

263 extern inline int strlen(const char * s)

264 {

265 register int __res __asm__("cx");    // __res是寄存器变量(ecx)

266 __asm__("cld\n\t"                    // 清方向位�

267         "repne\n\t"                  // al(0)与字符串中字�es:[edi]比较�

268         "scasb\n\t"                  // 若不相等就一直比较�

269         "notl %0\n\t"                // ecx取反�

270         "decl %0"                    // ecx--,得字符串得长度值�

271         :"=c" (__res):"D" (s),"a" (0),"0" (0xffffffff):"di");

272 return __res;                        // 返回字符串长度值�

273 }

274

275 extern char * ___strtok;     // 用于临时存放指向下面被分析字符串1(s)的指针�

276

    //// 利用字符�2中的字符将字符串1分割成标�(tokern)序列�

    // 将串1看作是包含零个或多个单词(token)的序列,并由分割符字符串2中的一个或多个字符

    // 分开。第一次调� strtok()时,将返回指向字符串1中第1token首字符的指针,并在返

    // token时将一 null字符写到分割符处。后续使� null 作为字符�1的调用,将用这种�

    // 法继续扫描字符串1,直到没�token 为止。在不同的调用过程中,分割符�2可以不同�

    // 参数�s - 待处理的字符�1ct - 包含各个分割符的字符�2

    // 汇编输出�%0 - ebx(__res)%1 - esi(__strtok)

    // 汇编输入�%2 - ebx(__strtok)%3 - esi(字符�1指针s)%4 - (字符�2指针ct)

    // 返回:返回字符串s中第1token,如果没有找�token,则返回一�null指针�

    // 后续使用字符�s指针�null的调用,将在原字符串s中搜索下一�token

277 extern inline char * strtok(char * s,const char * ct)

278 {

279 register char * __res __asm__("si");

280 __asm__("testl %1,%1\n\t"            // 首先测试esi(字符�1指针s)是否�NULL

281         "jne 1f\n\t"                 // 如果不是,则表明是首次调用本函数,跳转标�1

282         "testl %0,%0\n\t"            // 若是NULL,表示此次是后续调用,测ebx(__strtok)

283         "je 8f\n\t"                  // 如果ebx指针�NULL,则不能处理,跳转结束�

284         "movl %0,%1\n"               // ebx指针复制�esi

285         "1:\txorl %0,%0\n\t"         // ebx指针�

286         "movl $-1,%%ecx\n\t"         // ecx = 0xffffffff

287         "xorl %%eax,%%eax\n\t"       // 清零eax

288         "cld\n\t"                    // 清方向位�

289         "movl %4,%%edi\n\t"          // 下面求字符串2的长度�edi指向字符�2

290         "repne\n\t"                  // al(0)es:[edi]比较,并�edi++

291         "scasb\n\t"                  // 直到找到字符�2的结�null字符,或计数ecx==0

292         "notl %%ecx\n\t"             // ecx取反�

293         "decl %%ecx\n\t"             // ecx--,得到字符串2的长度值�

294         "je 7f\n\t"                  /* empty delimeter-string */

                                         /* 分割符字符串� */ // 若串2长度�0,则转标�7

295         "movl %%ecx,%%edx\n"         // 将串2长度暂存�edx

296         "2:\tlodsb\n\t"              // 取串1的字�ds:[esi]èal,并�esi++

297         "testb %%al,%%al\n\t"        // 该字符为0值吗(1结束)

298         "je 7f\n\t"                  // 如果是,则跳转标�7

299         "movl %4,%%edi\n\t"          // edi再次指向�2首�

300         "movl %%edx,%%ecx\n\t"       // 取串2的长度值置入计数器ecx

301         "repne\n\t"                  // al中串1的字符与�2中所有字符比较,

302         "scasb\n\t"                  // 判断该字符是否为分割符�

303         "je 2b\n\t"                  // 若能在串2中找到相同字符(分割符),则跳转标号2

304         "decl %1\n\t"                // 若不是分割符,则�1指针esi指向此时的该字符�

305         "cmpb $0,(%1)\n\t"           // 该字符是NULL字符吗?

306         "je 7f\n\t"                  // 若是,则跳转标号7处�

307         "movl %1,%0\n"               // 将该字符的指�esi存放�ebx

308         "3:\tlodsb\n\t"              // 取串1下一个字�ds:[esi]èal,并�esi++

309         "testb %%al,%%al\n\t"        // 该字符是NULL字符吗?

310         "je 5f\n\t"                  // 若是,表示串1结束,跳转到标号5

311         "movl %4,%%edi\n\t"          // edi再次指向�2首�

312         "movl %%edx,%%ecx\n\t"       // 2长度值置入计数器ecx

313         "repne\n\t"                  // al中串1的字符与�2中每个字符比较,

314         "scasb\n\t"                  // 测试al字符是否是分割符�

315         "jne 3b\n\t"                 // 若不是分割符则跳转标�3,检测串1中下一个字符�

316         "decl %1\n\t"                // 若是分割符,�esi--,指向该分割符字符�

317         "cmpb $0,(%1)\n\t"           // 该分割符�NULL字符吗?

318         "je 5f\n\t"                  // 若是,则跳转到标�5

319         "movb $0,(%1)\n\t"           // 若不是,则将该分割符�NULL字符替换掉�

320         "incl %1\n\t"                // esi指向�1中下一个字符,也即剩余串首�

321         "jmp 6f\n"                   // 跳转标号6处�

322         "5:\txorl %1,%1\n"           // esi清零�

323         "6:\tcmpb $0,(%0)\n\t"       // ebx指针指向NULL字符吗?

324         "jne 7f\n\t"                 // 若不是,则跳转标�7

325         "xorl %0,%0\n"               // 若是,则�ebx=NULL

326         "7:\ttestl %0,%0\n\t"        // ebx指针�NULL吗?

327         "jne 8f\n\t"                 // 若不是则跳转8,结束汇编代码�

328         "movl %0,%1\n"               // esi置为NULL

329         "8:"

330         :"=b" (__res),"=S" (___strtok)

331         :"0" (___strtok),"1" (s),"g" (ct)

332         :"ax","cx","dx","di");

333 return __res;                        // 返回指向�token的指针�

334 }

335

    //// 内存块复制。从源地址src处开始复�n个字节到目的地址dest处�

    // 参数�dest - 复制的目的地址�src - 复制的源地址�n - 复制字节数�

    // %0 - ecx(n)%1 - esi(src)%2 - edi(dest)

336 extern inline void * memcpy(void * dest,const void * src, int n)

337 {

338 __asm__("cld\n\t"                    // 清方向位�

339         "rep\n\t"                    // 重复执行复制ecx个字节,

340         "movsb"                      // ds:[esi]es:[edi]esi++edi++

341         ::"c" (n),"S" (src),"D" (dest)

342         :"cx","si","di");

343 return dest;                         // 返回目的地址�

344 }

345

    //// 内存块移动。同内存块复制,但考虑移动的方向�

    // 参数�dest - 复制的目的地址�src - 复制的源地址�n - 复制字节数�

    // dest<src则:%0 - ecx(n)%1 - esi(src)%2 - edi(dest)

    // 否则�%0 - ecx(n)%1 - esi(src+n-1)%2 - edi(dest+n-1)

    // 这样操作是为了防止在复制时错误地重叠覆盖�

346 extern inline void * memmove(void * dest,const void * src, int n)

347 {

348 if (dest<src)

349 __asm__("cld\n\t"                    // 清方向位�

350         "rep\n\t"                    // ds:[esi]es:[edi],并�esi++edi++

351         "movsb"                      // 重复执行复制ecx字节�

352         ::"c" (n),"S" (src),"D" (dest)

353         :"cx","si","di");

354 else

355 __asm__("std\n\t"                    // 置方向位,从末端开始复制�

356         "rep\n\t"                    // ds:[esi]es:[edi],并�esi--edi--

357         "movsb"                      // 复制ecx个字节�

358         ::"c" (n),"S" (src+n-1),"D" (dest+n-1)

359         :"cx","si","di");

360 return dest;

361 }

362

    //// 比较n个字节的两块内存(两个字符串),即使遇上NULL字节也不停止比较�

    // 参数�cs - 内存�1地址�ct - 内存�2地址�count - 比较的字节数�

    // %0 - eax(__res)%1 - eax(0)%2 - edi(内存�1)%3 - esi(内存�2)%4 - ecx(count)

    // 返回:若�1>2 返回1;块1<2,返�-1;块1==2,则返回0

363 extern inline int memcmp(const void * cs,const void * ct,int count)

364 {

365 register int __res __asm__("ax");    // __res是寄存器变量�

366 __asm__("cld\n\t"                    // 清方向位�

367         "repe\n\t"                   // 如果相等则重复,

368         "cmpsb\n\t"                  // 比较ds:[esi]es:[edi]的内容,并且esi++edi++

369         "je 1f\n\t"                  // 如果都相同,则跳转到标号1,返�0(eax)

370         "movl $1,%%eax\n\t"          // 否则eax1

371         "jl 1f\n\t"                  // 若内存块2内容的�<内存�1,则跳转标号1

372         "negl %%eax\n"               // 否则eax = -eax

373         "1:"

374         :"=a" (__res):"0" (0),"D" (cs),"S" (ct),"c" (count)

375         :"si","di","cx");

376 return __res;                        // 返回比较结果�

377 }

378

    //// n字节大小的内存块(字符�)中寻找指定字符�

    // 参数�cs - 指定内存块地址�c - 指定的字符,count - 内存块长度�

    // %0 - edi(__res)%1 - eax(字符c)%2 - edi(内存块地址cs)%3 - ecx(字节�count)

    // 返回第一个匹配字符的指针,如果没有找到,则返�NULL字符�

379 extern inline void * memchr(const void * cs,char c,int count)

380 {

381 register void * __res __asm__("di"); // __res是寄存器变量�

382 if (!count)                          // 如果内存块长�==0,则返回NULL,没有找到�

383         return NULL;

384 __asm__("cld\n\t"                    // 清方向位�

385         "repne\n\t"                  // 如果不相等则重复执行下面语句�

386         "scasb\n\t"                  // al中字符与es:[edi]字符作比较,并且edi++

387         "je 1f\n\t"                  // 如果相等则向前跳转到标号1处�

388         "movl $1,%0\n"               // 否则edi中置1

389         "1:\tdecl %0"                // edi指向找到的字符(或是NULL)�

390         :"=D" (__res):"a" (c),"D" (cs),"c" (count)

391         :"cx");

392 return __res;                        // 返回字符指针�

393 }

394

    //// 用字符填写指定长度内存块�

    // 用字�c填写s指向的内存区域,共填count字节�

    // %0 - eax(字符c)%1 - edi(内存地址)%2 - ecx(字节�count)

395 extern inline void * memset(void * s,char c,int count)

396 {

397 __asm__("cld\n\t"                    // 清方向位�

398         "rep\n\t"                    // 重复ecx指定的次数,执行

399         "stosb"                      // al中字符存�es:[edi]中,并且edi++

400         ::"a" (c),"D" (s),"c" (count)

401         :"cx","di");

402 return s;

403 }

404

405 #endif

406