一开始觉得implode挺容易实现,但是写着写着才发现是挺复杂的,不说啦 来看看implode的用法吧 1 ? php 2 $arr = array ('Hello','World!','Beautiful','Day!' ); 3 echo implode (" ", $arr ); 4 ? 上面会输出 Hello World! Beautiful Day! 下面的程序的我写
一开始觉得implode挺容易实现,但是写着写着才发现是挺复杂的,不说啦
来看看implode的用法吧
<span>1</span> <span>php </span><span>2</span> <span>$arr</span> = <span>array</span>('Hello','World!','Beautiful','Day!'<span>); </span><span>3</span> <span>echo</span> <span>implode</span>(" ",<span>$arr</span><span>); </span><span>4</span> ?>
上面会输出 Hello World! Beautiful Day!Copy after login
下面的程序的我写的
<span> 1</span> <span>/*</span><span>字符串翻转</span><span>*/</span> <span> 2</span> <span>void</span> strover(<span>char</span> *<span> str){ </span><span> 3</span> <span>int</span> len =<span> strlen(str); </span><span> 4</span> <span>//</span><span>int half = strlen(str)/2;</span> <span> 5</span> <span>int</span><span> i,j; </span><span> 6</span> <span>char</span><span> tmp; </span><span> 7</span> j = len-<span>1</span><span>; </span><span> 8</span> <span>for</span>(i=<span>0</span>;i){ <span> 9</span> tmp =<span> str[j]; </span><span>10</span> str[j] =<span> str[i]; </span><span>11</span> str[i] =<span> tmp; </span><span>12</span> j--<span>; </span><span>13</span> <span> } </span><span>14</span> <span>15</span> <span>16</span> <span>} </span><span>17</span> <span>18</span> <span>19</span> <span>20</span> <span>21</span> <span>22</span> <span>/*</span> <span>23</span> <span> 2进制转十进制 要处理正负数啊 涉及到负数啊 </span><span>24</span> <span> 字符串翻转 </span><span>25</span> <span>*/</span> <span>26</span> <span>char</span> * bin2decimal(<span>int</span><span> number){ </span><span>27</span> <span>28</span> <span>int</span> q = <span>0</span>; <span>//</span><span>商</span> <span>29</span> <span>int</span> r = <span>0</span>;<span>//</span><span>余数</span> <span>30</span> <span>int</span> i = <span>0</span><span>; </span><span>31</span> <span>int</span> tmp =<span> number; </span><span>32</span> <span>int</span> is_negative = <span>0</span><span>; </span><span>33</span> <span>char</span> *<span> res; </span><span>34</span> res = (<span>char</span> *)malloc(<span>sizeof</span>(<span>char</span>)*<span>5</span>+<span>1</span><span>); </span><span>35</span> <span>if</span>(number>=<span>0</span><span>){ </span><span>36</span> <span>37</span> }<span>else</span><span>{ </span><span>38</span> tmp = -<span>number; </span><span>39</span> res[i++] = <span>'</span><span>-</span><span>'</span><span>; </span><span>40</span> is_negative = <span>1</span><span>; </span><span>41</span> <span> } </span><span>42</span> <span>43</span> <span>do</span><span>{ </span><span>44</span> q = tmp/<span>10</span><span>; </span><span>45</span> <span>46</span> r = tmp%<span>10</span><span>; </span><span>47</span> <span>//</span><span> tmp = q; </span><span>48</span> <span>//</span><span> c = hex_str[r];</span> <span>49</span> res[i++] = <span>'</span><span>0</span><span>'</span>+<span>r; </span><span>50</span> tmp =<span> q; </span><span>51</span> }<span>while</span><span>(tmp); </span><span>52</span> <span>53</span> res[i] = <span>'</span><span>\0</span><span>'</span><span>; </span><span>54</span> <span>55</span> strover(&<span>res[is_negative]); </span><span>56</span> <span>return</span><span> res; </span><span>57</span> <span>58</span> <span>59</span> <span>} </span><span>60</span> <span>61</span> <span>62</span> <span>63</span> <span>64</span> <span>/*</span> <span>65</span> <span> c语言真的太麻烦啦,传数组,但是无法知道数组的长度,只能够手动传入 </span><span>66</span> <span>*/</span> <span>67</span> <span>char</span> * implode(<span>int</span> *number,<span>int</span> size,<span>char</span> *<span> dem){ </span><span>68</span> <span>int</span> i = <span>0</span><span>; </span><span>69</span> <span>char</span>*<span> c; </span><span>70</span> <span>//</span><span>c[1] = '\0';</span> <span>71</span> <span>struct</span><span> simple_mem{ </span><span>72</span> <span>char</span> *<span> res; </span><span>73</span> unsigned <span>int</span><span> len; </span><span>74</span> unsigned <span>int</span><span> used; </span><span>75</span> <span> }test_mem; </span><span>76</span> test_mem.res = (<span>char</span> *)malloc(<span>sizeof</span>(<span>char</span>)*<span>20</span><span>); </span><span>77</span> test_mem.len = <span>sizeof</span>(<span>char</span>)*<span>20</span><span>; </span><span>78</span> test_mem.used = <span>0</span><span>; </span><span>79</span> <span>for</span>(;isize;){ <span>80</span> c=<span> bin2decimal(number[i]); </span><span>81</span> memcpy(test_mem.res+<span>test_mem.used,c,strlen(c)); </span><span>82</span> <span>83</span> test_mem.used+=<span>strlen(c); </span><span>84</span> <span>if</span>(++isize){ <span>85</span> memcpy(test_mem.res+<span>test_mem.used,dem,strlen(dem)); </span><span>86</span> test_mem.used+=<span>strlen(dem); </span><span>87</span> <span> } </span><span>88</span> <span>89</span> <span> } </span><span>90</span> test_mem.res[test_mem.used] = <span>'</span><span>\0</span><span>'</span><span>; </span><span>91</span> printf(<span>"</span><span>%s</span><span>"</span><span>,test_mem.res); </span><span>92</span> <span>93</span> <span>94</span> }
我们写的implode写的函数是针对整形数组,php的当然什么类型都支持啊,c语言也可以实现泛型,但毕竟比较麻烦的,上面的程序还是比较多问题的,优化的地方有很多,但是我们是抱着学习的态度来的
<span> 1</span> <span>int</span><span> main(){ </span><span> 2</span> <span>//</span><span>char * res = bin2hex("a"); </span><span> 3</span> <span>//</span><span>printf("hex a=%s",res); </span><span> 4</span> <span>//</span><span>char * res = hex2bin("6578616d706c65206865782064617461");</span> <span> 5</span> <span>int</span> integer[<span>3</span>] = {<span>1</span>,-<span>24</span>,<span>3</span><span>}; </span><span> 6</span> implode(integer,<span>sizeof</span>(integer)/<span>sizeof</span>(<span>int</span>),<span>"</span><span>*</span><span>"</span><span>); </span><span> 7</span> <span> 8</span> <span>//</span><span>bin2decimal(-1234);</span> <span> 9</span> <span>10</span> <span>return</span> <span>0</span><span>; </span><span>11</span> }
先说说思路吧
1,主要是算法是2进制转10进制 字符串显示,当然我们要注意负数啦,还有字符串翻转
2 内存分配,因为我们没有限制数组的长度,所以我们要动态去分配,其实我们可以有一样可以确定的是整形的范围 0到65535 就是说一个整形最多占5个字符,
3 其他就没什么啦
来看看php的吧
<span> 1</span> <span>/*</span> <span> 2</span> <span> * Convert num to its decimal format. </span><span> 3</span> <span> * Return value: </span><span> 4</span> <span> * - a pointer to a string containing the number (no sign) </span><span> 5</span> <span> * - len contains the length of the string </span><span> 6</span> <span> * - is_negative is set to TRUE or FALSE depending on the sign </span><span> 7</span> <span> * of the number (always set to FALSE if is_unsigned is TRUE) </span><span> 8</span> <span> * </span><span> 9</span> <span> * The caller provides a buffer for the string: that is the buf_end argument </span><span>10</span> <span> * which is a pointer to the END of the buffer + 1 (i.e. if the buffer </span><span>11</span> <span> * is declared as buf[ 100 ], buf_end should be &buf[ 100 ]) </span><span>12</span> <span>*/</span> <span>13</span> <span>/*</span><span> char * ap_php_conv_10() {{{ </span><span>*/</span> <span>14</span> <span>char</span> *<span> ap_php_conv_10(register wide_int num, register bool_int is_unsigned, </span><span>15</span> register bool_int * is_negative, <span>char</span> *buf_end, register <span>int</span> *<span>len) </span><span>16</span> <span>{ </span><span>17</span> register <span>char</span> *p =<span> buf_end; </span><span>18</span> <span> register u_wide_int magnitude; </span><span>19</span> <span>20</span> <span>if</span><span> (is_unsigned) { </span><span>21</span> magnitude =<span> (u_wide_int) num; </span><span>22</span> *is_negative =<span> FALSE; </span><span>23</span> } <span>else</span><span> { </span><span>24</span> *is_negative = (num 0<span>); </span><span>25</span> <span>26</span> <span>/*</span> <span>27</span> <span> * On a 2's complement machine, negating the most negative integer </span><span>28</span> <span> * results in a number that cannot be represented as a signed integer. </span><span>29</span> <span> * Here is what we do to obtain the number's magnitude: </span><span>30</span> <span> * a. add 1 to the number </span><span>31</span> <span> * b. negate it (becomes positive) </span><span>32</span> <span> * c. convert it to unsigned </span><span>33</span> <span> * d. add 1 </span><span>34</span> <span>*/</span> <span>35</span> <span>if</span> (*<span>is_negative) { </span><span>36</span> wide_int t = num + <span>1</span><span>; </span><span>37</span> magnitude = ((u_wide_int) - t) + <span>1</span><span>; </span><span>38</span> } <span>else</span><span> { </span><span>39</span> magnitude =<span> (u_wide_int) num; </span><span>40</span> <span> } </span><span>41</span> <span> } </span><span>42</span> <span>43</span> <span>/*</span> <span>44</span> <span> * We use a do-while loop so that we write at least 1 digit </span><span>45</span> <span>*/</span> <span>46</span> <span>do</span><span> { </span><span>47</span> register u_wide_int new_magnitude = magnitude / <span>10</span><span>; </span><span>48</span> <span>49</span> *--p = (<span>char</span>)(magnitude - new_magnitude * <span>10</span> + <span>'</span><span>0</span><span>'</span><span>); </span><span>50</span> magnitude =<span> new_magnitude; </span><span>51</span> <span> } </span><span>52</span> <span>while</span><span> (magnitude); </span><span>53</span> <span>54</span> *len = buf_end -<span> p; </span><span>55</span> <span>return</span><span> (p); </span><span>56</span> }
> php5ts_debug.dll!ap_php_conv_10(__int64 num=-278, int is_unsigned=0, int * is_negative=0x00c3e154, char * buf_end=0x00c3e9c0, int * len=0x00c3ea64) 行320 C
php5ts_debug.dll!format_converter(buf_area * odp=0x00c3eb9c, const char * fmt=0x105d799e, char * ap=0x00c3ecc0) 行869 + 0x34 字节 C
php5ts_debug.dll!strx_printv(int * ccp=0x00c3eca0, char * buf=0x00c3ee90, unsigned int len=12, const char * format=0x105d799c, char * ap=0x00c3ecbc) 行1213 + 0x11 字节 C
php5ts_debug.dll!ap_php_slprintf(char * buf=0x00c3ee90, unsigned int len=12, const char * format=0x105d799c, ...) 行1229 + 0x19 字节 C
php5ts_debug.dll!php_implode(_zval_struct * delim=0x030dffd8, _zval_struct * arr=0x030dff88, _zval_struct * return_value=0x030e0028, void * * * tsrm_ls=0x00353040) 行1154 + 0x1b 字节 C
php5ts_debug.dll!zif_implode(int ht=2, _zval_struct * return_value=0x030e0028, _zval_struct * * return_value_ptr=0x00000000, _zval_struct * this_ptr=0x00000000, int return_value_used=1, void * * * tsrm_ls=0x00353040) 行1250 + 0x15 字节 C
php5ts_debug.dll!zend_do_fcall_common_helper_SPEC(_zend_execute_data * execute_data=0x030c20d8, void * * * tsrm_ls=0x00353040) 行643 + 0x62 字节 C
php5ts_debug.dll!ZEND_DO_FCALL_SPEC_CONST_HANDLER(_zend_execute_data * execute_data=0x030c20d8, void * * * tsrm_ls=0x00353040) 行2234 C
php5ts_debug.dll!execute(_zend_op_array * op_array=0x030dfa40, void * * * tsrm_ls=0x00353040) 行410 + 0x11 字节 C
php5ts_debug.dll!zend_execute_scripts(int type=8, void * * * tsrm_ls=0x00353040, _zval_struct * * retval=0x00000000, int file_count=3, ...) 行1329 + 0x21 字节 C
php5ts_debug.dll!php_execute_script(_zend_file_handle * primary_file=0x00c3fcf4, void * * * tsrm_ls=0x00353040) 行2502 + 0x1b 字节 C
php.exe!do_cli(int argc=2, char * * argv=0x00352fa0, void * * * tsrm_ls=0x00353040) 行989 + 0x10 字节 C
php.exe!main(int argc=2, char * * argv=0x00352fa0) 行1365 + 0x11 字节 C
调用堆栈如上
<span>1</span> <span>do</span><span> { </span><span>2</span> register u_wide_int new_magnitude = magnitude / <span>10</span><span>; </span><span>3</span> <span>4</span> *--p = (<span>char</span>)(magnitude - new_magnitude * <span>10</span> + <span>'</span><span>0</span><span>'</span><span>); </span><span>5</span> magnitude =<span> new_magnitude; </span><span>6</span> <span> } </span><span>7</span> <span>while</span> (magnitude);
关键是这段代码,作者没有像我们 用取余去计算,而是 把它乘,举个例子吧
magnitude = 283
new_magnitude = 283/10 = 28
*--p = 283 - 28*10+'0' = '3'
magnitude = new_magnitude = 28
然后继续上面的步骤啦
取余考虑和乘法考虑那个高,不知道作者的想法是怎样的,有时间用汇编证明一下,那个用的指令比较多
第二个的就是 作者用了倒序字符复制 *--p,这就要读读内存的代码啦
<strong>*len = buf_end -</strong><span><strong> p; 字符串长度可以这样计算的,指针的作用就是不错啊<br></strong><br>回到调用的地方如下<br><br></span>
<span> 1</span> s = ap_php_conv_10(i_num, (*fmt) == <span>'</span><span>u</span><span>'</span>, &<span>is_negative, </span><span> 2</span> &num_buf[NUM_BUF_SIZE], &<span>s_len); </span><span> 3</span> <span> FIX_PRECISION(adjust_precision, precision, s, s_len); </span><span> 4</span> <span> 5</span> <span>if</span> (*fmt != <span>'</span><span>u</span><span>'</span><span>) { </span><span> 6</span> <span>if</span><span> (is_negative) { </span><span> 7</span> prefix_char = <span>'</span><span>-</span><span>'</span><span>; </span><span> 8</span> } <span>else</span> <span>if</span><span> (print_sign) { </span><span> 9</span> prefix_char = <span>'</span><span>+</span><span>'</span><span>; </span><span>10</span> } <span>else</span> <span>if</span><span> (print_blank) { </span><span>11</span> prefix_char = <span>'</span> <span>'</span><span>; </span><span>12</span> <span> } </span><span>13</span> <span> } </span><span>14</span> <span>break</span>;
num_buf[NUM_BUF_SIZE] 这个东西长度为2048,不知道为什么要分配这么多的内存<br><br>上面的判断就是看看是不是负数,然后就 赋给修饰符<br><br>
if (prefix_char != NUL) { *--s = prefix_char; s_len++; }
应该很容易吧
下面来看下一层的调用
<span> 1</span> <span>while</span> (zend_hash_get_current_data_ex(Z_ARRVAL_P(arr), (<span>void</span> **) &tmp, &pos) ==<span> SUCCESS) { </span><span> 2</span> <span>switch</span> ((*tmp)-><span>type) { </span><span> 3</span> <span>case</span><span> IS_STRING: </span><span> 4</span> smart_str_appendl(&<span>implstr, Z_STRVAL_PP(tmp), Z_STRLEN_PP(tmp)); </span><span> 5</span> <span>break</span><span>; </span><span> 6</span> <span> 7</span> <span>case</span><span> IS_LONG: { </span><span> 8</span> <span>char</span> stmp[MAX_LENGTH_OF_LONG + <span>1</span><span>]; </span><span> 9</span> str_len = slprintf(stmp, <span>sizeof</span>(stmp), <span>"</span><span>%ld</span><span>"</span><span>, Z_LVAL_PP(tmp)); </span><span>10</span> smart_str_appendl(&<span>implstr, stmp, str_len); </span><span>11</span> <span> } </span><span>12</span> <span>break</span><span>; </span><span>13</span> <span>14</span> <span>case</span><span> IS_BOOL: </span><span>15</span> <span>if</span> (Z_LVAL_PP(tmp) == <span>1</span><span>) { </span><span>16</span> smart_str_appendl(&implstr, <span>"</span><span>1</span><span>"</span>, <span>sizeof</span>(<span>"</span><span>1</span><span>"</span>)-<span>1</span><span>); </span><span>17</span> <span> } </span><span>18</span> <span>break</span><span>; </span><span>19</span> <span>20</span> <span>case</span><span> IS_NULL: </span><span>21</span> <span>break</span><span>; </span><span>22</span> <span>23</span> <span>case</span><span> IS_DOUBLE: { </span><span>24</span> <span>char</span> *<span>stmp; </span><span>25</span> str_len = spprintf(&stmp, <span>0</span>, <span>"</span><span>%.*G</span><span>"</span>, (<span>int</span><span>) EG(precision), Z_DVAL_PP(tmp)); </span><span>26</span> smart_str_appendl(&<span>implstr, stmp, str_len); </span><span>27</span> <span> efree(stmp); </span><span>28</span> <span> } </span><span>29</span> <span>break</span><span>; </span><span>30</span> <span>31</span> <span>case</span><span> IS_OBJECT: { </span><span>32</span> <span>int</span><span> copy; </span><span>33</span> <span> zval expr; </span><span>34</span> zend_make_printable_zval(*tmp, &expr, &<span>copy); </span><span>35</span> smart_str_appendl(&<span>implstr, Z_STRVAL(expr), Z_STRLEN(expr)); </span><span>36</span> <span>if</span><span> (copy) { </span><span>37</span> zval_dtor(&<span>expr); </span><span>38</span> <span> } </span><span>39</span> <span> } </span><span>40</span> <span>break</span><span>; </span><span>41</span> <span>42</span> <span>default</span><span>: </span><span>43</span> tmp_val = **<span>tmp; </span><span>44</span> zval_copy_ctor(&<span>tmp_val); </span><span>45</span> convert_to_string(&<span>tmp_val); </span><span>46</span> smart_str_appendl(&<span>implstr, Z_STRVAL(tmp_val), Z_STRLEN(tmp_val)); </span><span>47</span> zval_dtor(&<span>tmp_val); </span><span>48</span> <span>break</span><span>; </span><span>49</span> <span>50</span> }
我们是在这段代码
case IS_LONG: {
char stmp[MAX_LENGTH_OF_LONG + 1];
str_len = slprintf(stmp, sizeof(stmp), "%ld", Z_LVAL_PP(tmp));
smart_str_appendl(&implstr, stmp, str_len);
}
+ &implstr 0x00c3ef04 {c=0x030e0100 "1.5-" len=4 a=78 } smart_str *
+ stmp 0x00c3ee90 "-278" char [12]
str_len 4 int
+ tmp 0x030e0924 _zval_struct * *
php数字默认类型是长整形的,从上面可知道,stmp="-278",strlen = 4,
我们接下来看看implstr是这样处理的,首先他的结构是这样的
<span>1</span> typedef <span>struct</span><span> { </span><span>2</span> <span>char</span> *<span>c; 指向一段内存 </span><span>3</span> <span> size_t len; 已经用了多小 </span><span>4</span> <span> size_t a; 总共有多小 </span><span>5</span> } smart_str;
smart_str_appendl 的定义是这样的<br><br>
<span>1</span> <span>#define</span> smart_str_appendl_ex(dest, src, nlen, what) do { \ <span>2</span> <span> register size_t __nl; \ </span><span>3</span> smart_str *__dest = (smart_str *<span>) (dest); \ </span><span>4</span> <span> \ </span><span>5</span> <span> smart_str_alloc4(__dest, (nlen), (what), __nl); \ </span><span>6</span> memcpy(__dest->c + __dest-><span>len, (src), (nlen)); \ </span><span>7</span> __dest->len =<span> __nl; \ </span><span>8</span> } <span>while</span> (<span>0</span>)
复制字符串用了memcpy
smart_str_alloc4这个定义如下
<span> 1</span> <span>#define</span> smart_str_alloc4(d, n, what, newlen) do { \ <span> 2</span> <span>if</span> (!(d)-><span>c) { \ </span><span> 3</span> (d)->len = <span>0</span><span>; \ </span><span> 4</span> newlen =<span> (n); \ </span><span> 5</span> (d)->a = newlen SMART_STR_START_SIZE \ <span> 6</span> ?<span> SMART_STR_START_SIZE \ </span><span> 7</span> : newlen +<span> SMART_STR_PREALLOC; \ </span><span> 8</span> <span> SMART_STR_DO_REALLOC(d, what); \ </span><span> 9</span> } <span>else</span><span> { \ </span><span>10</span> newlen = (d)->len +<span> (n); \ </span><span>11</span> <span>if</span> (newlen >= (d)-><span>a) { \ </span><span>12</span> (d)->a = newlen +<span> SMART_STR_PREALLOC; \ </span><span>13</span> <span> SMART_STR_DO_REALLOC(d, what); \ </span><span>14</span> <span> } \ </span><span>15</span> <span> } \ </span><span>16</span> } <span>while</span> (<span>0</span>)
这个很清楚啦流程啦
如果implstr 没有分配过的,那么闲分配一段内存
如果implstr分配过,并且当前的空间不够容纳新的字符 在这基础上扩展啦 SMART_STR_PREALLOC =78 不知道为什么是78
看下定义吧
1 #define SMART_STR_DO_REALLOC(d, what) \
2 (d)->c = SMART_STR_REALLOC((d)->c, (d)->a + 1, (what))
1 #define SMART_STR_REALLOC(a,b,c) perealloc((a),(b),(c))
1 #define perealloc(ptr, size, persistent) ((persistent)?__zend_realloc((ptr), (size)):erealloc((ptr), (size)))
<span>1</span> inline <span>static</span> <span>void</span> * __zend_realloc(<span>void</span> *<span>p, size_t len) </span><span>2</span> <span>{ </span><span>3</span> p =<span> realloc(p, len); </span><span>4</span> <span>if</span><span> (p) { </span><span>5</span> <span>return</span><span> p; </span><span>6</span> <span> } </span><span>7</span> fprintf(stderr, <span>"</span><span>Out of memory\n</span><span>"</span><span>); </span><span>8</span> exit(<span>1</span><span>); </span><span>9</span> }
最终是调用了 c语言的realloc函数,这样就大概明白了吧
到最后加上分割符号
1 if (++i != numelems) {
2 smart_str_appendl(&implstr, Z_STRVAL_P(delim), Z_STRLEN_P(delim));
3 }
上面是分析了整数的implode,至于浮点数,对象,字符串 的implode大家可以用上面的方法去研究下