0
#include <ctype.h>
#include <string.h>
#include <stdio.h>
#include <tgmath.h>
#include <limits.h>
#include <stdbool.h>
#include <errno.h>
#define NEGATIVE -1
#define POSITIVE 1
#define OCTAL 8
#define DECIMAL 10
#define HEXADECIMAL 16
#define BASE_MIN 2
#define BASE_MAX 36
long int strtol (const char * str, char ** endPtr, int base)
{
    if(base < 0 ||  base == 1 || base > BASE_MAX)
    {
        errno = EINVAL;
        return 0L;
    }
    else
    {
        bool conversion = true;
        int i = 0, sign = POSITIVE, save;
        while(isspace(*(str + i)))
            i++;
        if(*(str + i) == '\0')
        {
            conversion = false;
            save = i;
        }
        if(*(str + i) == '-')
        {
            sign = NEGATIVE;
            i++;
        }
        else if(*(str + i) == '+')
            i++;
        if(base == 0) // find out base
        {
            if(*(str + i) == '0')
            {
                if(toupper(*(str + i + 1)) == 'X')
                {
                    base = HEXADECIMAL;
                    i++;
                }
                else
                    base = OCTAL;
                i++;
            }
            else
                base = DECIMAL;
        }
        else if(base == OCTAL)
        {
            if(*(str + i) == '0')
                i++;
        }
        else if(base == HEXADECIMAL)
        {
            if(*(str + i) == '0')
                if(*(str + i + 1) == 'x' || *(str + i + 1) == 'X')
                    i += 2;
        }
        int start = i, end, exp, check = i;
        long int long_int, sum, multiplier;
        if(conversion) // find out the correct part of the string corresponding to the number
        {
            if(base < DECIMAL)
            {
                while(*(str + i) >= '0' && *(str + i) < base + '0') // numbers from 0 to base - 1
                    i++;
            }
            else if(base == DECIMAL)
            {
                while(*(str + i) >= '0' && *(str + i) <= '9') // numbers from 0 to 9
                    i++;
            }
            else
            {
                while((*(str + i) >= '0' && *(str + i) <= '9') || (toupper(*(str + i)) >= 'A' && toupper(*(str + i)) < 'A' + base - 10))
                        i++;// numbers from 0 to 9 and uper and lowercase letters from a to a + base - 11
            }
        }
        if(i == check && conversion) //no digits at all
        {
            conversion = false;
            save = i;
        }
        else if(endPtr != NULL && conversion) // assign pointer
            *endPtr = (char *) (str + i);
        if(conversion)
        {
            for(end = i - 1, exp = 0, long_int = 0L; end >= start; end--, exp++)
            {
                multiplier = pow(base, exp);
                sum = 0L;
                if(*(str + end) >= '0' && *(str + end) <= '9') 
                    sum = (*(str + end) - '0') * multiplier;
                else if(*(str + end) >= 'A' && *(str + i) <= (base == BASE_MAX ? 'Z' : 'F')) 
                    sum = (*(str + end) - 'A' + 10) * multiplier;
                else if(*(str + end) >= 'a' && *(str + i) <= (base == BASE_MAX ? 'z' : 'f'))
                    sum = (*(str + end) - 'a' + 10) * multiplier;
                if(long_int <= LONG_MIN + sum)
                {
                    errno = ERANGE;
                    return LONG_MIN;
                }
                if(long_int >= LONG_MAX - sum)
                {
                    errno = ERANGE;
                    return LONG_MAX;
                }
                else
                    long_int += sum;
            }
            return sign * long_int;
        }
        else
        {
            if(endPtr != NULL)
            {// if base is 16 we check if the string given is not in the form 0xIncorrect string in that way we need to return xIncorrect part of the string
                if(base == HEXADECIMAL && save >= 2 && toupper(*(str + save - 1)) == 'X' && *(str + save - 2) == '0')
                    *endPtr = (char *) str + save - 1;
                else if(base == OCTAL && save >= 1 && *(str + save - 1) == '0')
                    *endPtr = (char *) str + save;// if the string is of base 8 and in the form 0incorrect string
                else                            //then we return everything after the 0 as the endptr string
                    *endPtr = (char *) str;//in other cases no conversion was done so we return original pointer
            }
            return 0L;
        }
    }
}

我在编写 strtol() 函数的实现时遇到了问题。问题是我在 64 位机器上编译它并且输出是正确的,但是今天我在另一台 32 位机器上检查它并且出现了问题。32 位机器显示结果,例如字符串“7FFFFFFF”超出范围,而在 64 位机器上,结果是 strtol 成功,这与标准函数相同。我还检查了 errno 值,对于 32 位机器,它设置为 ERANGE,这不应该是,它不是不在 64 位上。我有一个程序可以检查您的实现是否为不同字符串提供与标准输出相同的输出。我花了几个小时寻找可能的错误,但我没有想法?有小费吗?

4

0 回答 0