免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
楼主: duanjigang
打印 上一主题 下一主题

源码阅读第一期:axel和wget [复制链接]

论坛徽章:
0
81 [报告]
发表于 2011-10-01 23:42 |只看该作者
到今天为止,函数和数据结构的分析已经完成。

接下来对 搜索 和 下载 两部分的核心函数以及代码段做些分析,axel的分析就可以告一段落了。

论坛徽章:
0
82 [报告]
发表于 2011-10-02 10:30 |只看该作者
本帖最后由 duanjigang 于 2011-10-02 11:21 编辑

首先来看看搜索镜像文件这段代码:

  1. i = search_makelist( search, s );
  2.                 if( i < 0 )
  3.                 {
  4.                         fprintf( stderr, _("File not found\n" ) );
  5.                         return( 1 );
  6.                 }
  7.                 if( conf->verbose )
  8.                         printf( _("Testing speeds, this can take a while...\n") );
  9.                 //开始测速,其实就是看谁返回快
  10.                 j = search_getspeeds( search, i );
  11.                 //速度排序,按照时间由大到小排列,也就是速度由小到大排列
  12.                 search_sortlist( search, i );
复制代码
先看看search_makelist的分析:

  1. int search_makelist( search_t *results, char *url )
  2. {
  3.         int i, size = 8192, j = 0;
  4.         char *s, *s1, *s2, *s3;
  5.         conn_t conn[1];
  6.         double t;
  7.        
  8.         memset( conn, 0, sizeof( conn_t ) );
  9.        
  10.         conn->conf = results->conf;
  11.         t = gettime();
  12.         //源站点也算一个镜像,从此开始-----start
  13.         //填充连接的准备数据
  14.         if( !conn_set( conn, url ) )
  15.                 return( -1 );
  16.         //打开ftp或者http连接(ftp的话,要切换目录)
  17.         if( !conn_init( conn ) )
  18.                 return( -1 );
  19.         //获取文件信息。建立连接
  20.         if( !conn_info( conn ) )
  21.                 return( -1 );
  22.        
  23.         strcpy( results[0].url, url );
  24.         results[0].speed = 1 + 1000 * ( gettime() - t );//毫秒
  25.         results[0].size = conn->size;
  26.         //------源站点的搜索结束----finish
  27.         //因此,到目前为止,已经有一个资源链接了。

  28.         s = malloc( size );
  29.         //构造访问filesearching.com的URL地址
  30.         sprintf( s, "http://www.filesearching.com/cgi-bin/s?q=%s&w=a&l=en&"
  31.                 "t=f&e=on&m=%i&o=n&s1=%lld&s2=%lld&x=15&y=15",
  32.                 conn->file, results->conf->search_amount,
  33.                 conn->size, conn->size );
  34.        
  35.         //关掉原来的连接
  36.         conn_disconnect( conn );
  37.         memset( conn, 0, sizeof( conn_t ) );
  38.         conn->conf = results->conf;
  39.         //重新设置搜索的URL地址
  40.         if( !conn_set( conn, s ) )
  41.         {
  42.                 free( s );
  43.                 //因为已经有一个搜索返回结果了,因此需要返回1
  44.                 return( 1 );
  45.         }
  46.         if( !conn_setup( conn ) )
  47.         {
  48.                 free( s );
  49.                 return( 1 );
  50.         }
  51.         if( !conn_exec( conn ) )
  52.         {
  53.                 free( s );
  54.                 return( 1 );
  55.         }
  56.         //读取页面返回的结果
  57.         while( ( i = read( conn->fd, s + j, size - j ) ) > 0 )
  58.         {
  59.                 j += i;
  60.                 if( j + 10 >= size )
  61.                 {
  62.                         size *= 2;
  63.                         s = realloc( s, size );
  64.                         memset( s + size / 2, 0, size / 2 );
  65.                 }
  66.         }

  67.         conn_disconnect( conn );
  68.         //关闭连接后,从http结果中解析搜索到的资源
  69.         s1 = strstr( s, "<pre class=list" );//开始标志
  70.         s1 = strchr( s1, '\n' ) + 1;
  71.         if( strstr( s1, "</pre>" ) == NULL ) //结束标志
  72.         {
  73.                 /* Incomplete list                                        */
  74.                 free( s );
  75.                 return( 1 );
  76.         }
  77.         //可以打开filesearching.com搜索一个文件后,在结果界面中查看源代码,就能看到这个标签
  78.         //没发现</pre>就说明没结束,还有,没到搜索topN之前,继续走
  79.         /*
  80.         <pre class=list>
  81.         1 <img src=/img/icontxt.gif width=16 height=16> <b>    665</b> <a href=/cgi-bin/s?t=n&l=en&q=ftp.de.debian.org/ class=ls>ftp.de.debian.org</a><a href=/cgi-bin/s?t=n&l=en&q=ftp.de.debian.org/debian/dists/lenny/main/installer-amd64/20090123lenny8/images/netboot/debian-installer/amd64/boot-screens class=lg>/debian/dists/lenny/main/installer-amd64/20090123lenny8/images/netboot/debian-installer/amd64/boot-screens/</a><a href=ftp://ftp.de.debian.org/debian/dists/lenny/main/installer-amd64/20090123lenny8/images/netboot/debian-installer/amd64/boot-screens/f2.txt class=lf>f2.txt</a>
  82.         2 <img src=/img/icontxt.gif width=16 height=16> <b>    665</b> <a href=/cgi-bin/s?t=n&l=en&q=ftp.de.debian.org/ class=ls>ftp.de.debian.org</a><a href=/cgi-bin/s?t=n&l=en&q=ftp.de.debian.org/debian/dists/lenny/main/installer-amd64/20090123lenny8/images/netboot/gtk/debian-installer/amd64/boot-screens class=lg>/debian/dists/lenny/main/installer-amd64/20090123lenny8/images/netboot/gtk/debian-installer/amd64/boot-screens/</a><a href=ftp://ftp.de.debian.org/debian/dists/lenny/main/installer-amd64/20090123lenny8/images/netboot/gtk/debian-installer/amd64/boot-screens/f2.txt class=lf>f2.txt</a>
  83.         </pre>
  84.         */
  85.         //结束条件: 找到结束符号 or 查找条目数够了 or 读取的字符串无效
  86.         for( i = 1; strncmp( s1, "</pre>", 6 ) && i < results->conf->search_amount && *s1; i ++ )
  87.         {
  88.                 s3 = strchr( s1, '\n' ); *s3 = 0;
  89.                 //最后一个href=..是文件URL
  90.                 //s2=ftp://ftp.de.debian.org/debian/dists/lenny/main/installer-amd64/20090123lenny8/images/netboot/debian-installer/amd64/boot-screens/f2.txt class=lf>f2.txt</a>
  91.                 s2 = strrstr( s1, "<a href=" ) + 8;
  92.                
  93.                 *s3 = '\n';
  94.                 //找到URL后面的空格,改成结束符
  95.                 //s2变为:
  96. //ftp://ftp.de.debian.org/debian/dists/lenny/main/installer-amd64/20090123lenny8/images/netboot/debian-installer/amd64/boot-screens/f2.txt
  97. //一个完整的文件下载地址
  98.                 s3 = strchr( s2, ' ' ); *s3 = 0;
  99.                 if( strcmp( results[0].url, s2 ) )
  100.                 {
  101.                        
  102.                         strncpy( results[i].url, s2, MAX_STRING );
  103.                         results[i].size = results[0].size;
  104.                         results[i].conf = results->conf;
  105.                 }
  106.                 else
  107.                 {
  108.                         /* The original URL might show up                */
  109.                         i --;
  110.                 }
  111.                 //找到第一行结束回车符
  112.                 for( s1 = s3; *s1 != '\n'; s1 ++ );
  113.                 //第二行开头
  114.                 s1 ++;
  115.         }
  116.        
  117.         free( s );
  118.         //返回查找到的个数
  119.         return( i );
  120. }

复制代码

论坛徽章:
0
83 [报告]
发表于 2011-10-02 10:38 |只看该作者
回复 81# duanjigang
好快。。。。。。。

论坛徽章:
0
84 [报告]
发表于 2011-10-02 11:23 |只看该作者
回复  duanjigang
好快。。。。。。。
wangzhen11aaa 发表于 2011-10-02 10:38



    呵呵,好几年前axel早版本的代码大致扫过一遍,而且这个工程比较下,因此看起来快些。:wink:

论坛徽章:
0
85 [报告]
发表于 2011-10-02 11:32 |只看该作者
本帖最后由 duanjigang 于 2011-10-02 11:37 编辑

获取search到资源的访问速度 search_getspeeds

  1. int search_getspeeds( search_t *results, int count )
  2. {
  3.         int i, running = 0, done = 0, correct = 0;
  4.        
  5.         for( i = 0; i < count; i ++ ) if( results[i].speed )
  6.         {
  7.                
  8.                 results[i].speed_start_time = 0;
  9.                 //已经完成的个数
  10.                 done ++;
  11.                 //有效速度的个数
  12.                 if( results[i].speed > 0 )
  13.                         correct ++;
  14.         }

  15.         //没有全部搞定之前,一直循环
  16.         while( done < count )
  17.         {
  18.                 for( i = 0; i < count; i ++ )
  19.                 {
  20.                         //未有速度值 and 搜索线程还未全部启动起来
  21.                         if( running < results->conf->search_threads && !results[i].speed )
  22.                         {
  23.                                 results[i].speed = SPEED_ACTIVE;
  24.                                 results[i].speed_start_time = gettime();
  25.                                 if( pthread_create( results[i].speed_thread,
  26.                                         NULL, search_speedtest, &results[i] ) == 0 )
  27.                                 {
  28.                                         //一个线程又启动啦...
  29.                                         running ++;
  30.                                         break;
  31.                                 }
  32.                                 else //如果创建搜索线程失败,就直接返回
  33.                                 {
  34.                                         return( 0 );
  35.                                 }
  36.                         }//超时了,还未有速度
  37.                         else if( ( results[i].speed == SPEED_ACTIVE ) &&
  38.                                 ( gettime() > results[i].speed_start_time + results->conf->search_timeout ) )
  39.                         {
  40.                                 //停止线程
  41.                                 pthread_cancel( *results[i].speed_thread );
  42.                                 results[i].speed = SPEED_DONE;//速度小
  43.                                 running --;//减小运行线程的计数器
  44.                                 done ++; //不管成功还是失败,总算结束了。。。
  45.                                 break; //进入下一次检查
  46.                         }//返回了,就退出
  47.                         else //这一头没问题
  48.                                 if( results[i].speed > 0 && results[i].speed_start_time )
  49.                         {
  50.                                 results[i].speed_start_time = 0;
  51.                                 running --;
  52.                                 correct ++;
  53.                                 done ++;
  54.                                 break; //进入下一次检查
  55.                         }
  56.                         else if( results[i].speed == SPEED_ERROR )//获取失败
  57.                         {
  58.                                 results[i].speed = SPEED_DONE;
  59.                                 running --;
  60.                                 done ++;
  61.                                 break;//进入下一次检查
  62.                         }
  63.                 }
  64.                 //完整的检查了一遍,就休息下,如果是中途break的,直接立刻开始下一次检查
  65.                 if( i == count )
  66.                 {
  67.                         usleep( 100000 );
  68.                 }
  69.         }

  70.         return( correct );
  71. }
复制代码
可以看到,测试速度是通过多线程来实现的,多线程的函数体是 search_speedtest

这个函数并未通过下载文件来测试速度,而是把访问发出到返回结果的请求过程的时间间隔作为速度参考值,这是有道理的。

  1. void *search_speedtest( void *r )
  2. {
  3.         search_t *results = r;
  4.         conn_t conn[1];
  5.         int oldstate;
  6.        
  7.         /* Allow this thread to be killed at any time.                        */
  8.         pthread_setcancelstate( PTHREAD_CANCEL_ENABLE, &oldstate );
  9.         pthread_setcanceltype( PTHREAD_CANCEL_ASYNCHRONOUS, &oldstate );
  10.        
  11.         memset( conn, 0, sizeof( conn_t ) );
  12.         conn->conf = results->conf;
  13.         if( !conn_set( conn, results->url ) )
  14.                 results->speed = SPEED_ERROR;
  15.         else if( !conn_init( conn ) )
  16.                 results->speed = SPEED_ERROR;
  17.         else if( !conn_info( conn ) )
  18.                 results->speed = SPEED_ERROR;
  19.         else if( conn->size == results->size )
  20.                 /* Add one because it mustn't be zero                        */
  21.                 //时间越大,速度越小
  22.                 results->speed = 1 + 1000 * ( gettime() - results->speed_start_time );
  23.         else
  24.                 results->speed = SPEED_ERROR;

  25.         conn_disconnect( conn );
  26.        
  27.         return( NULL );
  28. }
复制代码

论坛徽章:
0
86 [报告]
发表于 2011-10-02 11:37 |只看该作者
本帖最后由 duanjigang 于 2011-10-02 11:43 编辑

search的最后一个函数 search_sortlist,镜像站点按照速度排序


对搜索到的站点按照速度从大到小排序,也就是访问时间从小到大排序,而axel中speed的值就是这个访问时间间隔。

search_sortlist采用快速排序算法,当然compare函数要自己写的。
以下两个函数实现了这一切。

  1. void search_sortlist( search_t *results, int count )
  2. {
  3.         qsort( results, count, sizeof( search_t ), search_sortlist_qsort );
  4. }

  5. int search_sortlist_qsort( const void *a, const void *b )
  6. {
  7.         if( ((search_t *)a)->speed < 0 && ((search_t *)b)->speed > 0 )
  8.                 return( 1 );
  9.         if( ((search_t *)a)->speed > 0 && ((search_t *)b)->speed < 0 )
  10.                 return( -1 );
  11.         if( ((search_t *)a)->speed < ((search_t *)b)->speed )
  12.                 return( -1 );
  13.         else
  14.                 return( ((search_t *)a)->speed > ((search_t *)b)->speed );
  15. }
复制代码
关于函数

  1. search_sortlist_qsort
复制代码
的用意,请参考31楼的分析。

search部分的核心基本上搞定了

论坛徽章:
0
87 [报告]
发表于 2011-10-02 11:44 |只看该作者
本帖最后由 wangzhen11aaa 于 2011-10-02 16:40 编辑

<---------_______________
关于test_path_simplify()这个函数是将路径化简为最有效并且等价的路径。也是为了减少运输的数据量,具体的各个模式化简方式以后讨论。
all_tests()

. . . . . .
mu_run_test(test_append_uri_pathel);  /*1、_______________----------->/usr/url.c*/
. . . . . .
}
1、_______________-------------->
const char *test_append_uri_pathel()
{
2212 {
2213   int i;
2214   struct {
2215     char *original_url;
2216     char *input;
2217     bool escaped;
2218     char *expected_result;
2219   } test_array[] = {
2220     { "http://www.yoyodyne.com/path/", "somepage.html", false, "http://www.yoyodyne.com/path/somepage.html" },
2221   };
2222 /*这里就检测一个url路径*/
2223   for (i = 0; i < sizeof(test_array)/sizeof(test_array[0]); ++i)
2224     {
2225       struct growable dest; /* 此和4的一样*/
2226       const char *p = test_array.input;
2227
2228       memset (&dest, 0, sizeof (dest));  /*这个lib库的函数*/
2229
2230       append_string (test_array.original_url, &dest); /*2、_____________------------>/src/url.c*/
2231       append_uri_pathel (p, p + strlen(p), test_array.escaped, &dest); /*3、___________---------->*/
2232       append_char ('\0', &dest);
2233
2234       mu_assert ("test_append_uri_pathel: wrong result",
2235                  strcmp (dest.base, test_array.expected_result) == 0);
2236     }
2237
2238   return NULL;
2239 }
2、_____________---------------->
1274 static void
1275 append_string (const char *str, struct growable *dest)
1276 {
1277   int l = strlen (str);  /*获得字符串长度*/
1278   GROW (dest, l);/*3、___________________------------->/src/url.c*/
1279   memcpy (TAIL (dest), str, l);/*7、_______------------>/src/url.c虽然分配了空间,但是还没有赋值所以末尾值还是0*/
1280   TAIL_INCR (dest, l); /*8、___________------------->/src/url.c,改变tail 的值*/
1281 }
3、___________________------------------->
1260 #define GROW(g, append_size) do {                                            \
1261   struct growable *G_ = g;  /*4、___________------------> /src/url.c*/                                                \
1262   DO_REALLOC (G_->base, G_->size, G_->tail + append_size, char); /*5 、____---->            \
1263 } while (0)
4、______________------------->
struct growable{
char *base;
int size;  /*初始化是这些值都是0*/
int tail;
}
5、_______________------------------->
#define DO_REALLOC(basevar, sizevar, needed_size, type) do{
299   long DR_needed_size = (needed_size);    /*这里是一个式子*/                              \
300   long DR_newsize = 0;                                                  \
301   while ((sizevar) < (DR_needed_size)) {                                \
302     DR_newsize = sizevar << 1;     /* 分配的大小是2^n,至少16个字节*/                               \
303     if (DR_newsize < 16)                                                \
304       DR_newsize = 16;                                                  \
305     (sizevar) = DR_newsize;                                             \
306   }                                                                     \
307   if (DR_newsize)                                                       \
308     basevar = xrealloc (basevar, DR_newsize * sizeof (type));  /*分配大小,这里出现了c++的类和c,当然我选择的是c6、____---------->lib/xmalloc.c*/         /*type 本来就是char 类型,为什么还要sizeof(type)?我觉得为了少出人为的错*/\
309 } while (0)
310
6、_______-------------->
52 void *
53 xrealloc (void *p, size_t n)
54 {
55   if (!n && p)
56     {
57      
59       free (p);
60       return NULL;
61     }
62
63   p = realloc (p, n);    /*分配在这里*/
64   if (!p && n)
65     xalloc_die ();  /*abort()*/
66   return p;
67 }
<---------------------------____________________________
GROW调用后,dest被初始化,类型中既有地址,而且有大小*/
7、_______________---------------->
#define TAIL(r) ((r)->base + (r)->tail)
8、_______------------>
#define  #define TAIL_INCR(r, append_count) ((r)->tail += append_count)
<------------------------------------______________________________________________
返回到 mu_run_test(test_append_uri_pathel()函数中
append_uri_pathel() _________----------->9、/src/url.c*/
1372 static void
1373 append_uri_pathel (const char *b, const char *e, bool escaped,
1374                    struct growable *dest)
1375 {
1376   const char *p;
1377   int quoted, outlen;
1378
1379   int mask;
1380   if (opt.restrict_files_os == restrict_unix)
1381     mask = filechr_not_unix;  /*判断unix类型*/
1382   else
1383     mask = filechr_not_windows;  
1384   if (opt.restrict_files_ctrl)
1385     mask |= filechr_control;
1386
1387  
1388   if (escaped)  /*如果期望值是1*/
1389     {
1390       char *unescaped;   
1391       BOUNDED_TO_ALLOCA (b, e, unescaped);/*10、______------->/src/wget.h*/
1392       url_unescape (unescaped);
1393       b = unescaped;
1394       e = unescaped + strlen (unescaped);
1395     }
1396
1397  
1398   
1399   if (e - b == 2 && b[0] == '.' && b[1] == '.')
1400     {
1401       b = "%2E%2E";
1402       e = b + 6;
1403     }
1404
1407   quoted = 0;
1408   for (p = b; p < e; p++)
1409     if (FILE_CHAR_TEST (*p, mask))
1410       ++quoted;
1411
1412   /* Calculate the length of the output string.  e-b is the input
1413      string length.  Each quoted char introduces two additional
1414      characters in the string, hence 2*quoted.  */
1415   outlen = (e - b) + (2 * quoted);
1416   GROW (dest, outlen);
1417
1418   if (!quoted)
1419     {
1420      
1421
1422       memcpy (TAIL (dest), b, outlen);
1423     }
1424   else
1425     {
1426       char *q = TAIL (dest);
1427       for (p = b; p < e; p++)
1428         {
1429           if (!FILE_CHAR_TEST (*p, mask))
1430             *q++ = *p;
1431           else
1432             {
1433               unsigned char ch = *p;
1434               *q++ = '%';
1435               *q++ = XNUM_TO_DIGIT (ch >> 4);
1436               *q++ = XNUM_TO_DIGIT (ch & 0xf);
1437             }
1438         }
1439       assert (q - TAIL (dest) == outlen);
1440  }
1443   if (opt.restrict_files_case == restrict_lowercase
1444       || opt.restrict_files_case == restrict_uppercase)
1445     {
1446       char *q;
1447       for (q = TAIL (dest); q < TAIL (dest) + outlen; ++q)
1448         {
1449           if (opt.restrict_files_case == restrict_lowercase)
1450             *q = c_tolower (*q);
1451           else
1452             *q = c_toupper (*q);
1453         }
1454     }
1455
1456   TAIL_INCR (dest, outlen);
1457 }
10、____________------------>
#define BOUNDED_TO_ALLOC(beg, end, place)   \
要装不下了。下移*/

论坛徽章:
0
88 [报告]
发表于 2011-10-02 17:22 |只看该作者
接着
257 #define BOUNDED_TO_ALLOCA(beg, end, place) do { \  
258   const char *BTA_beg = (beg);                  \
259   int BTA_len = (end) - BTA_beg;                \
260   char **BTA_dest = &(place);                   \
261   *BTA_dest = alloca (BTA_len + 1);             \/*alloca的作用是测试并返回堆栈空间的*/
262   memcpy (*BTA_dest, BTA_beg, BTA_len);         \
263   (*BTA_dest)[BTA_len] = '\0';                  \/*字符串末尾加\0*/
264 } while (0)
这段函数作用是在place指针指向位置拷贝字符串
<-------------------_____________
下面的函数为 url_unescape(char *s)  /*0、__________--------->/src/url.c*/
172 static void
173 url_unescape (char *s)
174 {
175   char *t = s;               
176   char *h = s;                 
177
178   for (; *h; h++, t++)  /*直到到达字符串的末尾*/
179     {
180       if (*h != '%')
181         {
182         copychar:            /*此处准备使用goto语句*/
183           *t = *h;   /*如果*h不是%,那么就拷贝到*t指向的位置*/
184         }
185       else
186         {
187           char c;
188           /* Do nothing if '%' is not followed by two hex digits. 如果%号后没有两个16进制的数*/
189           if (!h[1] || !h[2] || !(c_isxdigit (h[1]) && c_isxdigit (h[2]))) /*1、__-->lib/c-type.c*/
190             goto copychar;  /*就去拷贝*/
191           c = X2DIGITS_TO_NUM (h[1], h[2]); /*3、_______----->/src/wget.h*/
192           /* Don't unescape %00 because there is no way to insert it
193              into a C string without effectively truncating it. */
194           if (c == '\0')
195             goto copychar;
196           *t = c;
197           h += 2;
198         }
199     }
200   *t = '\0';
201 }
1、________--------->
效果很明显,不解释了*/
296 c_isxdigit (int c)
297 {
298 #if C_CTYPE_CONSECUTIVE_DIGITS \
299     && C_CTYPE_CONSECUTIVE_UPPERCASE && C_CTYPE_CONSECUTIVE_LOWERCASE
300 #if C_CTYPE_ASCII
301   return ((c >= '0' && c <= '9')
302           || ((c & ~0x20) >= 'A' && (c & ~0x20) <= 'F'));
303 #else
304   return ((c >= '0' && c <= '9')
305           || (c >= 'A' && c <= 'F')
306           || (c >= 'a' && c <= 'f'));
307 #endif
308 #else
309   switch (c)
310     {
311     case '0': case '1': case '2': case '3': case '4': case '5':
312     case '6': case '7': case '8': case '9':
313     case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
314     case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
315       return 1;
316     default:
317       return 0;
318     }
319 #endif
320 }
3、__________---------->
#define ((XDIGIT_TO_NUM (h1) << 4) + XDIGIT_TO_NUM (h2))  /*通知一下,这里的源代码中是XDIGT_TO是错误的,在/src/wget.h中246行*/
#define XDIGIT_TO_NUM(h) ((h) < 'A' ? (h) - '0' : c_toupper(h) - 'A' + 10)

论坛徽章:
0
89 [报告]
发表于 2011-10-02 17:26 |只看该作者
本帖最后由 wangzhen11aaa 于 2011-10-02 19:49 编辑

通知                                 
#define ((XDIGIT_TO_NUM (h1) << 4) + XDIGIT_TO_NUM (h2))  /*通知一下,这里的源代码中是XDIGT_TO是错误的,在/src/wget.h中246行*/

而且 :
好像有段程序有问题。
173 url_unescape (char *s)
174 {
175   char *t = s;                  /* t - tortoise */
176   char *h = s;                  /* h - hare     */
177
178   for (; *h; h++, t++)
179     {
180       if (*h != '%')
181         {
182         copychar:
183           *t = *h;
                                       /*这里我认为应该有个continue;*/
184         }
185       else
186         {                /*这里如果字符是%,而且后面的h[1]h[2]都是16进制的,那么不是会陷入死循环吗?*/
187           char c;
188           /* Do nothing if '%' is not followed by two hex digits. */
189           if (!h[1] || !h[2] || !(c_isxdigit (h[1]) && c_isxdigit (h[2])))
190             goto copychar;  /*这里goto copychar 了, 然后一直执行h[1]h[2]是16进制的判断?不是死循环吗?*/
191           c = X2DIGITS_TO_NUM (h[1], h[2]);

论坛徽章:
0
90 [报告]
发表于 2011-10-02 19:46 |只看该作者
回复 89# wangzhen11aaa
不会陷入死循环,因为是在if语句中,编译成汇编时在if模块里是不会跳转到else语句中的。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP