没有任何库的 C 字符串到 int
C string to int without any libraries
我正在尝试编写我的第一个内核模块,因此无法包含 atoi、strtol 等库。如果没有这些内置函数,我如何将字符串转换为 int?我试过了:
int num;
num = string[0] - '0';
这适用于第一个字符,但如果我删除 [0]
以尝试转换完整的字符串,它会给我一个警告:赋值从指针生成整数而不进行强制转换。那我该怎么办?
您无法删除 [0]。这意味着你正在从指针string
中减去'0',这是没有意义的。您仍然需要取消引用它:
num = string[i] - '0';
此函数跳过前导和尾随空格,处理一个可选的 +
/ -
符号,以及 returns 无效输入时的 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);
}
在创建您自己的字符串到 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;
}
字符串是 array
个字符,由地址 (a.k.a pointer
) 表示。
pointer
的值可能类似于 0xa1de2bdf
。这个值告诉我数组的开始位置。
你不能用 character
类型减去 pointer
类型(例如 0xa1de2bdf - 'b' 没有意义)。
要将字符串转换为数字,您可以试试这个:
//Find the length of the string
int len = 0;
while (str[len] != '[=10=]') {
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;
}
我把上面的代码写得比较通俗易懂。它假定您的字符串在最后一个有用字符的后面有一个空字符 ('\0')(这是一种很好的做法)。
此外,您可能需要检查该字符串是否实际上是仅包含数字(例如“0”、“1”、“2”等)的有效字符串。您可以通过在遍历字符串时包含 if... else..
语句来做到这一点。
在现代内核中你想使用 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 */
“无法包含库”--> 不清楚是否允许代码访问 INT_MAX
、INT_MIN
。如果不使用 INT_MAX
、INT_MIN
.[= 等语言提供的宏,无法 以完全可移植的方式确定 minimum/maximum 有符号整数21=]
使用INT_MAX
,INT_MIN
可用。否则我们可以 猜测 char
宽度是 8。我们可以猜测没有填充位。我们可以猜测整数是 2 的补码。有了这些合理的 假设 ,最小值和最大值定义如下。
注意:移入符号位是未定义的行为 (UB),所以不要那样做。
让我们添加另一个限制:制定适用于从 signed char
到 intmax_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或更高版本
我正在尝试编写我的第一个内核模块,因此无法包含 atoi、strtol 等库。如果没有这些内置函数,我如何将字符串转换为 int?我试过了:
int num;
num = string[0] - '0';
这适用于第一个字符,但如果我删除 [0]
以尝试转换完整的字符串,它会给我一个警告:赋值从指针生成整数而不进行强制转换。那我该怎么办?
您无法删除 [0]。这意味着你正在从指针string
中减去'0',这是没有意义的。您仍然需要取消引用它:
num = string[i] - '0';
此函数跳过前导和尾随空格,处理一个可选的 +
/ -
符号,以及 returns 无效输入时的 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);
}
在创建您自己的字符串到 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;
}
字符串是
array
个字符,由地址 (a.k.apointer
) 表示。pointer
的值可能类似于0xa1de2bdf
。这个值告诉我数组的开始位置。你不能用
character
类型减去pointer
类型(例如 0xa1de2bdf - 'b' 没有意义)。
要将字符串转换为数字,您可以试试这个:
//Find the length of the string
int len = 0;
while (str[len] != '[=10=]') {
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;
}
我把上面的代码写得比较通俗易懂。它假定您的字符串在最后一个有用字符的后面有一个空字符 ('\0')(这是一种很好的做法)。
此外,您可能需要检查该字符串是否实际上是仅包含数字(例如“0”、“1”、“2”等)的有效字符串。您可以通过在遍历字符串时包含 if... else..
语句来做到这一点。
在现代内核中你想使用 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 */
“无法包含库”--> 不清楚是否允许代码访问 INT_MAX
、INT_MIN
。如果不使用 INT_MAX
、INT_MIN
.[= 等语言提供的宏,无法 以完全可移植的方式确定 minimum/maximum 有符号整数21=]
使用INT_MAX
,INT_MIN
可用。否则我们可以 猜测 char
宽度是 8。我们可以猜测没有填充位。我们可以猜测整数是 2 的补码。有了这些合理的 假设 ,最小值和最大值定义如下。
注意:移入符号位是未定义的行为 (UB),所以不要那样做。
让我们添加另一个限制:制定适用于从 signed char
到 intmax_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或更高版本