#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <limits.h>
/* returns 1 on success, 0 on any kind of failure */
int parse_int(const char *text, int *out) {
char *end;
errno = 0;
long value = strtol(text, &end, 10);
if (end == text) {
return 0; /* no digits at all */
}
if (*end != '\0') {
return 0; /* trailing junk */
}
if (errno == ERANGE || value < INT_MIN || value > INT_MAX) {
return 0; /* out of range for an int */
}
*out = (int)value;
return 1;
}
int main(void) {
const char *tests[] = {"42", "-7", "hello", "", "9999999999", "12abc"};
int n = (int)(sizeof tests / sizeof tests[0]);
for (int i = 0; i < n; i++) {
int value;
if (parse_int(tests[i], &value)) {
printf("\"%s\" -> %d\n", tests[i], value);
} else {
printf("\"%s\" -> rejected\n", tests[i]);
}
}
return 0;
}
有三个细节保证了它的正确性。调用前的 errno = 0 很重要,因为库函数只会设置 errno,从不清除它,之前某次调用留下的旧值会被误认为是这次调用的失败。strtol 返回 long,它可能比 int 更宽,所以针对 INT_MIN/INT_MAX 的范围检查要和 ERANGE 分开。最后,用返回值表示是否成功、通过指针传出结果,是 C 函数表达“要么得到一个值,要么失败”的方式,因为返回值无法同时承担两项工作。
#include <stdio.h>
#include <ctype.h>
int main(void) {
char c = '7';
int digit = c - '0';
printf("char '%c' -> int %d\n", c, digit);
int value = 3;
char back = (char)(value + '0');
printf("int %d -> char '%c'\n", value, back);
return 0;
}
只有数字是这样的。字母并不保证连续,所以用 c - 'a' 做字母运算是不可移植的。相信这个减法结果之前,先用 isdigit 判断:
#include <stdio.h>
#include <ctype.h>
int main(void) {
char text[] = "a1b2c3";
int sum = 0;
for (int i = 0; text[i] != '\0'; i++) {
if (isdigit((unsigned char)text[i])) {
sum += text[i] - '0';
}
}
printf("digits sum to %d\n", sum);
return 0;
}