• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            今天微薄上看到 http://weibo.com/1401880315/AaNkykg6J#_rnd1379945435634

            左耳朵耗子:
            現在的程序員,連atoi()都不知道是什么了,沒事,那我改,不叫atoi()改叫StrToInt(),卻發現,好些人連ASCII碼都不知道是怎么一回事,沒事,我教會你。但最終卻發現怎么有這么多人連這樣簡單的程序都寫不好(包括有多年工作經驗的人)。“比技術更恐怖的是有一群不合格的程序員在使用這這些技術”。


            好久沒寫這么基本的代碼了,簡單嘗試寫了下, 結果花了半個小時,只寫了一個最基本功能的,通過后面的測試用例還花了不少時間進行調試修改。 
            INT StrToInt(const TCHAR* lpszValue)
            {
                assert(lpszValue != NULL);

                INT nLen = lstrlen(lpszValue);
                const TCHAR* pEnd = lpszValue + nLen;

                TCHAR* pCurrent = (TCHAR*)lpszValue;
                BOOL bNegative(FALSE);
                if(nLen >= 1)
                {
                    if(*pCurrent == _T('+'))
                    {
                        bNegative = FALSE;
                        pCurrent += 1;
                    }
                    else if(*pCurrent == _T('-'))
                    {
                        bNegative = TRUE;
                        pCurrent += 1;
                    }
                    else
                    {
                        bNegative = FALSE;
                    }
                }

                INT nBase(10);
                if(pEnd - pCurrent >= 2)
                {
                    if(pCurrent[0] == _T('0')
                        && ::toupper(pCurrent[1]) == _T('X'))
                    {
                        pCurrent += 2;
                        nBase = 16;
                    }
                }

                INT nRet(0);
                INT nValue(0);
                while(pCurrent != pEnd)
                {
                    TCHAR ch(*pCurrent);
                    if(ch >= _T('0') && ch <= _T('9'))
                    {
                        nValue = ch - _T('0');
                    }
                    else if(nBase == 16)
                    {
                        if(::toupper(ch) >= _T('A') && ::toupper(ch) <= _T('F'))
                        {
                            nValue = 10 + (::toupper(ch) - _T('A'));
                        }
                        else
                        {
                            assert(FALSE);
                            break;
                        }
                    }
                    else
                    {
                        assert(FALSE);
                        break;
                    }

                    nRet += nValue * pow((double)nBase, pEnd - pCurrent - 1);
                    pCurrent += 1;
                }

                return bNegative ?  -nRet : nRet;
            }

            void test
            {
                assert(StrToInt(_T("11")) == 11);
                assert(StrToInt(_T("+12")) == 12); 
                assert(StrToInt(_T("-123")) == -123); 
                assert(StrToInt(_T("-0x1CF")) == -0x1CF); 
                assert(StrToInt(_T("-0X123")) == -0x123); 
                assert(StrToInt(_T("0X123")) == 0x123);
            }

            感慨用慣了Windows API和STL, 對于最基本的字符串處理代碼反而寫不好了。細想一下這個基本的東西確實不好寫, 實際上我是上面只是考慮了10進制和16進制, 沒有考慮其他進制,也沒有考慮小數,非法的字符串或是溢出等情況, 而真正工業級的庫要考慮所有的情況, 另外還要考慮轉換效率等問題。

            實際上CRT源碼中有這個函數的實現:
            /***
            *wcstol, wcstoul(nptr,endptr,ibase) - Convert ascii string to long un/signed
            *       int.
            *
            *Purpose:
            *       Convert an ascii string to a long 32-bit value.  The base
            *       used for the caculations is supplied by the caller.  The base
            *       must be in the range 0, 2-36.  If a base of 0 is supplied, the
            *       ascii string must be examined to determine the base of the
            *       number:
            *           (a) First char = '0', second char = 'x' or 'X',
            *               use base 16.
            *           (b) First char = '0', use base 8
            *           (c) First char in range '1' - '9', use base 10.
            *
            *       If the 'endptr' value is non-NULL, then wcstol/wcstoul places
            *       a pointer to the terminating character in this value.
            *       See ANSI standard for details
            *
            *Entry:
            *       nptr == NEAR/FAR pointer to the start of string.
            *       endptr == NEAR/FAR pointer to the end of the string.
            *       ibase == integer base to use for the calculations.
            *
            *       string format: [whitespace] [sign] [0] [x] [digits/letters]
            *
            *Exit:
            *       Good return:
            *           result
            *
            *       Overflow return:
            *           wcstol -- LONG_MAX or LONG_MIN
            *           wcstoul -- ULONG_MAX
            *           wcstol/wcstoul -- errno == ERANGE
            *
            *       No digits or bad base return:
            *           0
            *           endptr = nptr*
            *
            *Exceptions:
            *       Input parameters are validated. Refer to the validation section of the function.
            *
            *******************************************************************************/

            /* flag values */
            #define FL_UNSIGNED   1       /* wcstoul called */
            #define FL_NEG        2       /* negative sign found */
            #define FL_OVERFLOW   4       /* overflow occured */
            #define FL_READDIGIT  8       /* we've read at least one correct digit */


            static unsigned long __cdecl wcstoxl (
                    _locale_t plocinfo,
                    const wchar_t *nptr,
                    const wchar_t **endptr,
                    int ibase,
                    int flags
                    )
            {
                const wchar_t *p;
                wchar_t c;
                unsigned long number;
                unsigned digval;
                unsigned long maxval;
                _LocaleUpdate _loc_update(plocinfo);


                /* validation section */
                if (endptr != NULL)
                {
                    /* store beginning of string in endptr */
                    *endptr = nptr;
                }
                _VALIDATE_RETURN(nptr != NULL, EINVAL, 0L);
                _VALIDATE_RETURN(ibase == 0 || (2 <= ibase && ibase <= 36), EINVAL, 0L);

                p = nptr;           /* p is our scanning pointer */
                number = 0;         /* start with zero */

                c = *p++;           /* read char */

                while ( _iswspace_l(c, _loc_update.GetLocaleT()) )
                    c = *p++;       /* skip whitespace */

                if (c == '-') {
                    flags |= FL_NEG;    /* remember minus sign */
                    c = *p++;
                }
                else if (c == '+')
                    c = *p++;       /* skip sign */

                if (ibase == 0) {
                    /* determine base free-lance, based on first two chars of
                       string */
                    if (_wchartodigit(c) != 0)
                        ibase = 10;
                    else if (*p == L'x' || *p == L'X')
                        ibase = 16;
                    else
                        ibase = 8;
                }

                if (ibase == 16) {
                    /* we might have 0x in front of number; remove if there */
                    if (_wchartodigit(c) == 0 && (*p == L'x' || *p == L'X')) {
                        ++p;
                        c = *p++;   /* advance past prefix */
                    }
                }

                /* if our number exceeds this, we will overflow on multiply */
                maxval = ULONG_MAX / ibase;


                for (;;) {  /* exit in middle of loop */

                    /* convert c to value */
                    if ( (digval = _wchartodigit(c)) != -1 )
                        ;
                    else if ( __ascii_iswalpha(c))
                        digval = __ascii_towupper(c) - L'A' + 10;
                    else
                        break;

                    if (digval >= (unsigned)ibase)
                        break;      /* exit loop if bad digit found */

                    /* record the fact we have read one digit */
                    flags |= FL_READDIGIT;

                    /* we now need to compute number = number * base + digval,
                       but we need to know if overflow occured.  This requires
                       a tricky pre-check. */

                    if (number < maxval || (number == maxval &&
                    (unsigned long)digval <= ULONG_MAX % ibase)) {
                        /* we won't overflow, go ahead and multiply */
                        number = number * ibase + digval;
                    }
                    else {
                        /* we would have overflowed -- set the overflow flag */
                        flags |= FL_OVERFLOW;
                        if (endptr == NULL) {
                            /* no need to keep on parsing if we
                               don't have to return the endptr. */
                            break;
                        }
                    }

                    c = *p++;       /* read next digit */
                }

                --p;                /* point to place that stopped scan */

                if (!(flags & FL_READDIGIT)) {
                    /* no number there; return 0 and point to beginning of
                       string */
                    if (endptr)
                        /* store beginning of string in endptr later on */
                        p = nptr;
                    number = 0L;        /* return 0 */
                }
                else if ( (flags & FL_OVERFLOW) ||
                      ( !(flags & FL_UNSIGNED) &&
                        ( ( (flags & FL_NEG) && (number > -LONG_MIN) ) ||
                          ( !(flags & FL_NEG) && (number > LONG_MAX) ) ) ) )
                {
                    /* overflow or signed overflow occurred */
                    errno = ERANGE;
                    if ( flags & FL_UNSIGNED )
                        number = ULONG_MAX;
                    else if ( flags & FL_NEG )
                        number = (unsigned long)(-LONG_MIN);
                    else
                        number = LONG_MAX;
                }

                if (endptr != NULL)
                    /* store pointer to char that stopped the scan */
                    *endptr = p;

                if (flags & FL_NEG)
                    /* negate result if there was a neg sign */
                    number = (unsigned long)(-(long)number);

                return number;          /* done. */
            }

            透過這道題確實可以投射出一個程序員的計算機基本功, 大家可以自己嘗試下實現這個函數, 看看自己的計算機基本功。
            posted on 2013-09-23 22:39 Richard Wei 閱讀(2754) 評論(0)  編輯 收藏 引用 所屬分類: C++
            亚洲中文字幕无码久久精品1| 久久影院久久香蕉国产线看观看| 亚洲一级Av无码毛片久久精品| 精品久久国产一区二区三区香蕉 | 中文字幕无码久久精品青草| 久久久久久久91精品免费观看| 国产亚洲精品久久久久秋霞| 狠狠色丁香婷婷久久综合不卡| 久久久久久毛片免费看| 人妻无码精品久久亚瑟影视| 国产精品久久久久久一区二区三区| 久久久久久亚洲精品无码| 蜜臀av性久久久久蜜臀aⅴ| 久久国产三级无码一区二区| 久久亚洲精品国产精品| 尹人香蕉久久99天天拍| 99久久精品国产毛片| 人妻精品久久无码专区精东影业| 久久久久亚洲精品无码网址| 国产精品久久精品| 久久婷婷五月综合97色| 2019久久久高清456| 久久久久亚洲AV无码专区网站| 99久久婷婷免费国产综合精品| 久久久久久久波多野结衣高潮| 精品久久人人做人人爽综合| 亚洲嫩草影院久久精品| 国产精品一久久香蕉国产线看观看| 久久无码人妻精品一区二区三区| 99久久精品毛片免费播放| 狠狠色综合网站久久久久久久高清| 日韩AV毛片精品久久久| 精品久久久久久无码中文野结衣| 精品久久久久久国产91| 久久99中文字幕久久| 久久精品国产一区二区三区日韩| 国产国产成人精品久久| 久久久久人妻精品一区二区三区 | 日韩精品久久久久久| 伊人久久大香线焦AV综合影院| 久久精品国产99国产精品亚洲 |