C字符串为int而没有任何库

时间:2016-02-24 02:07:52

标签: c casting kernel

我试图编写我的第一个内核模块,因此我无法为atoi,strtol等包含库。如何在没有这些内置函数的情况下将字符串转换为int?我试过了:

int num;
num = string[0] - '0';

适用于第一个字符,但是如果我删除[0]以尝试转换完整字符串,它会给我一个警告:赋值从指针生成整数而没有强制转换。那我该怎么办?

6 个答案:

答案 0 :(得分:1)

在创建自己的字符串到int函数时,请确保检查并防止溢出。例如:

/* an atoi replacement performing the conversion in a single
   pass and incorporating 'err' to indicate a failed conversion.
   passing NULL as error causes it to be ignored */
int strtoi (const char *s, unsigned char *err)
{
    char *p = (char *)s;
    int nmax = (1ULL << 31) - 1;    /* INT_MAX  */
    int nmin = -nmax - 1;           /* INT_MIN  */
    long long sum = 0;
    char sign = *p;

    if (*p == '-' || *p == '+') p++;

    while (*p >= '0' && *p <= '9') {
        sum = sum * 10 - (*p - '0');
        if (sum < nmin || (sign != '-' && -sum > nmax)) goto error;
        p++;
    }

    if (sign != '-') sum = -sum;

    return (int)sum;

error:

    fprintf (stderr, "strtoi() error: invalid conversion for type int.\n");
    if (err) *err = 1;
    return 0;
}

答案 1 :(得分:0)

您无法移除[0]。这意味着你正在减去&#39; 0&#39; 0指针string,这是没有意义的。您仍然需要取消引用它: num = string[i] - '0';

答案 2 :(得分:0)

此函数会跳过前导和尾随空格,处理一个可选的+ / -符号,并在无效输入时返回0,

// Convert standard null-terminated string to an integer
// - Skips leading whitespaces.
// - Skips trailing whitespaces.
// - Allows for one, optional +/- sign at the front.
// - Returns zero if any non-+/-, non-numeric, non-space character is encountered.
// - Returns zero if digits are separated by spaces (eg "123  45")
// - Range is checked against Overflow/Underflow (INT_MAX / INT_MIN), and returns 0.
int StrToInt(const char* s)
{
    int minInt = 1 << (sizeof(int)*CHAR_BIT-1);
    int maxInt = -(minInt+1);
    char* w;

    do { // Skip any leading whitespace
        for(w=" \t\n\v\f\r"; *w && *s != *w; ++w) ;
        if (*s == *w) ++s; else break;
    } while(*s);

    int sign = 1;
    if ('-' == *s) sign = -1; 
    if ('+' == *s || '-' == *s) ++s;

    long long i=0;
    while('0' <= *s && *s <= '9')
    {
        i = 10*i + *s++ - '0';
        if (sign*i < minInt || maxInt < sign*i)
        {
            i = 0;
            break;
        }
    }

    while (*s) // Skip any trailing whitespace
    {
        for(w=" \t\n\v\f\r"; *w && *s != *w; ++w) ;
        if (*w && *s == *w) ++s; else break;
    }

    return (int)(!*s*sign*i);
}

答案 3 :(得分:0)

  1. 字符串是array个字符,由地址(a.k.a pointer)表示。

  2. pointer的值可能类似于0xa1de2bdf。这个值告诉我数组的起始位置。

  3. 您无法使用pointer类型减去character类型(例如,0xa1de2bdf - &#39; b&#39;实际上没有意义)。

  4. 要将字符串转换为数字,您可以尝试:

    //Find the length of the string
    int len = 0;
    while (str[len] != '\0') { 
       len++;
    }
    
    //Loop through the string
    int num = 0, i = 0, digit;
    for (i=0; i<len; i++) {
    
       //Extract the digit
       digit = ing[i] - '0';
    
       //Multiply the digit with its correct position (ones, tens, hundreds, etc.)
       num += digit * pow(10, (len-1)-i);
    }
    

    当然,如果您不允许使用math.h库,则可以编写自己的pow(a,b)函数,该函数会为您提供a^b的值。

    int mypowfunc(int a, int b) {
       int i=0, ans=1;
       //multiply the value a for b number of times
       for (i=0; i<b; i++) {
          ans *= a;
       }   
       return ans;
    }
    

    我以一种易于理解的方式编写了上面的代码。它假设你的字符串在最后一个有用的字符后面有一个空字符(&#39; \ 0&#39;)(这是一种很好的做法)。

    另外,您可能需要检查字符串实际上是否只包含数字的有效字符串(例如&#39; 0&#39;,&#39; 1&#39;,&#39; 2&#39;,等等。)。您可以通过在循环字符串时包含if... else..语句来完成此操作。

答案 4 :(得分:0)

在现代内核中,您想使用kstrto*

http://lxr.free-electrons.com/source/include/linux/kernel.h#L274

274 /**
275  * kstrtoul - convert a string to an unsigned long
276  * @s: The start of the string. The string must be null-terminated, and may also
277  *  include a single newline before its terminating null. The first character
278  *  may also be a plus sign, but not a minus sign.
279  * @base: The number base to use. The maximum supported base is 16. If base is
280  *  given as 0, then the base of the string is automatically detected with the
281  *  conventional semantics - If it begins with 0x the number will be parsed as a
282  *  hexadecimal (case insensitive), if it otherwise begins with 0, it will be
283  *  parsed as an octal number. Otherwise it will be parsed as a decimal.
284  * @res: Where to write the result of the conversion on success.
285  *
286  * Returns 0 on success, -ERANGE on overflow and -EINVAL on parsing error.
287  * Used as a replacement for the obsolete simple_strtoull. Return code must
288  * be checked.
289 */

答案 5 :(得分:0)

&#34;不能包括图书馆&#34; - &GT;不清楚是否允许代码访问INT_MAXINT_MIN无法以完全可移植的方式确定最小/最大有符号整数,而不使用INT_MAXINT_MIN等语言提供的宏。

使用INT_MAXINT_MIN可用。否则我们可以猜测 char宽度为8.我们可以猜测没有填充位。我们可以猜测整数是2的补码。通过这些合理的假设,最小值和最大值定义如下。

注意:转移到符号位是未定义的行为(UB),所以不要这样做。

让我们添加另一个限制:制定适用于从signed charintmax_t的任何有符号整数的解决方案。这不允许代码使用更宽的类型,因为可能没有更宽的类型。

typedef int Austin_int;

#define Austin_INT_MAXMID ( ((Austin_int)1) << (sizeof(Austin_int)*8 - 2) )
#define Austin_INT_MAX (Austin_INT_MAXMID - 1 + Austin_INT_MAXMID)
#define Austin_INT_MIN (-Austin_INT_MAX - 1)

int Austin_isspace(int ch) {
  const char *ws = " \t\n\r\f\v";
  while (*ws) {
    if (*ws == ch) return 1;
    ws++;
  }
  return 0;
}

// *endptr points to where parsing stopped
// *errorptr indicates overflow
Austin_int Austin_strtoi(const char *s, char **endptr, int *errorptr) {
  int error = 0;
  while (Austin_isspace(*s)) {
    s++;
  }

  char sign = *s;
  if (*s == '-' || *s == '+') {
    s++;
  }

  Austin_int sum = 0;
  while (*s >= '0' && *s <= '9') {
    int ch = *s - '0';
    if (sum <= Austin_INT_MIN / 10 &&
        (sum < Austin_INT_MIN / 10 || -ch < Austin_INT_MIN % 10)) {
      sum = Austin_INT_MIN;
      error = 1;
    } else {
      sum = sum * 10 - ch;
    }
    s++;
  }

  if (sign != '-') {
    if (sum < -Austin_INT_MAX) {
      sum = Austin_INT_MAX;
      error = 1;
    } else {
      sum = -sum;
    }
  }

  if (endptr) {
    *endptr = (char *) s;
  }
  if (errorptr) {
    *errorptr = error;
  }
  return sum;
}

以上内容取决于Austin_INT_MIN Austin_INT_MIN % 10部分中的C99或更高版本。