C 在实现我自己的Atoi()时有一些bug
我不明白。当我的函数从主函数的char返回随机数时。原始atoi()返回-1。我目前使用的是C11版本。我从某人那里听说,这是因为int溢出,我需要从我的函数返回int,但我现在返回long。如果不是2147483647,如何检测到InOverflowC 在实现我自己的Atoi()时有一些bug,c,c11,atoi,C,C11,Atoi,我不明白。当我的函数从主函数的char返回随机数时。原始atoi()返回-1。我目前使用的是C11版本。我从某人那里听说,这是因为int溢出,我需要从我的函数返回int,但我现在返回long。如果不是2147483647,如何检测到InOverflow #include <stdio.h> #include <stdlib.h> #include <stdbool.h> bool mx_isdigit(int c) { return c >=
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
bool mx_isdigit(int c) {
return c >= 48 && c <= 57;
}
bool mx_isspace(char c) {
return (c >= 9 && c <= 13) || c == 32;
}
int mx_atoi(const char *str) {
long num = 0;
int sign = 1;
for (; mx_isspace(*str); str++);
if (*str == '-' || *str == '+') {
sign = *str == '-' ? -sign : sign;
str++;
}
for (; *str; str++) {
if (!mx_isdigit(*str)) {
break;
}
num = (num * 10) + (*str - '0');
}
return sign == -1 ? -num : 0 + num;
}
int main(void) {
char str[100] = "12327123061232712306";
printf("R: %d\n", atoi(str));
printf("M: %d", mx_atoi(str));
}
#包括
#包括
#包括
布尔mx_isdigit(内部c){
返回c>=48&&c=9&&c在函数int mx_atoi(const char*str){…
中,您正在计算long
类型的结果,但函数返回int
;因此如果num
中存储的long
类型的结果不适合int
类型,则会丢失某些内容(实际上,由于有符号整数值被转换,行为是“实现定义的”,即依赖于编译器)。结果可能被逐位截断,产生一个“看起来”与您输入的十进制数大不相同的数字。参见,例如,在线C11草稿。粗体段落适用于:
6.3.1.3有符号和无符号整数
1当整数类型的值转换为其他整数类型时
除了_Bool,如果值可以用新类型表示,则
没有变化
2否则,如果新类型是无符号的,则该值由
重复地加上或减去一个大于最大值
可以在新类型中表示,直到值在
新型号(60)
3否则,将对新类型进行签名,并且无法删除该值
在其中表示;结果要么是定义的实现,要么是
执行定义的信号被触发。
将int-mx_-atoi(const-char*str)
转换为long-mx_-atoi(const-char*str)
,使用long
-变量存储结果,不要忘记在printf
中使用格式说明符%ld
而不是%d
否则,如果您需要坚持使用int
,并且希望安全地对溢出做出反应,您可以执行以下操作
if (num > INT_MAX) {
return -1;
}
在循环内部。INT\u MAX
在函数INT mx\u atoi(const char*str)内部的limits.h
中定义{…
,您正在计算long
类型的结果,但函数返回一个int
;因此,如果num
中存储的long
类型的结果不适合int
类型,则会丢失一些内容(实际上,由于符号整数值被转换,行为是“实现定义的”),即编译器相关)。结果可以按位截断,生成的数字“看起来”与您输入的十进制数字大不相同。参见,例如,联机C11草稿。粗体段落适用于:
6.3.1.3有符号和无符号整数
1当整数类型的值转换为其他整数类型时
除了_Bool,如果值可以用新类型表示,则
没有变化
2否则,如果新类型是无符号的,则该值由
重复地加上或减去一个大于最大值
可以在新类型中表示,直到值在
新型号(60)
3否则,将对新类型进行签名,并且无法删除该值
在其中表示;结果要么是定义的实现,要么是
执行定义的信号被触发。
将int-mx_-atoi(const-char*str)
转换为long-mx_-atoi(const-char*str)
,使用long
-变量存储结果,不要忘记在printf
中使用格式说明符%ld
而不是%d
否则,如果您需要坚持使用int
,并且希望安全地对溢出做出反应,您可以执行以下操作
if (num > INT_MAX) {
return -1;
}
在循环内部。INT\u MAX
在limits.h中定义
c>=48&&c
c>=48&&cint
溢出可能性
num=(num*10)+(*str-“0”);
遇到int
溢出,这是未定义的行为(UB),当:
1) 输入字符串应表示INT\u MIN
和INT/long
具有相同的范围或
2) 输入字符串对int
范围之外的值进行编码
避免这种情况的各种方法
未检测到无数字字符串
在这种情况下返回0是合理的,但代码可能需要设置一些错误条件
不抱怨尾随的非数字
简单地忽略尾随字符是合理的,但代码可能需要设置一些错误条件
避免int
溢出的一种方法(不要依赖long
比int
宽)是在(num*10)+(*str-'0')
之前进行测试,因为负int
比正多,所以在负的一侧进行累积
bool digit_found = false;
int val = 0;
for (; mx_isdigit(*str); str++) {
digit_found = true;
int digit = *str - '\0';
if (val <= INT_MIN/10 && (val < INT_MIN/10 || digit > -(INT_MIN%10))) { // C99
return sign == 1 ? INT_MAX : INT_MIN;
}
val = val * 10 - digit; // note subtraction here
}
if (!digit_found) {
return 0; // Or handle in some other fashion
}
if (sign == 1) {
// If val is too negative to negate ...
if (val < -INT_MAX) {
return INT_MAX; // overflow
}
return -val;
}
return val;
bool digit\u found=false;
int-val=0;
对于(;mx_isdigit(*str);str++){
找到的数字=真;
整数位数=*str-'\0';
如果(val-(INT_MIN%10)){//C99
返回符号==1?整数最大值:整数最小值;
}
val=val*10位;//注意这里的减法
}
如果(!找到数字){
返回0;//或以其他方式返回句柄
}
如果(符号==1){
//如果val太负而不能否定。。。
如果(val<-INT_MAX){
返回INT_MAX;//溢出
}
返回值-val;
}
返回val;
int
溢出可能性
num=(num*10)+(*str-“0”);
遇到int
溢出,这是未定义的行为(UB),当:
1) 输入字符串应表示INT\u MIN
和INT/long
具有相同的范围或
2) 输入字符串对int
范围之外的值进行编码
多种方式
int mx_atoi(const char *str) {
for (; mx_isspace(*str); str++);
bool negative = false;
if (*str == '-' || *str == '+') {
negative = *str == '-';
str++;
}
int num = 0;
for (; mx_isdigit(*str); str++) {
if (INT_MAX / 10 < num) {
goto ERR_OVERFLOW;
}
num *= 10;
const unsigned char c = *str - '0';
if (INT_MAX - c < num) {
goto ERR_OVERFLOW;
}
num += c;
}
return negative ? -num : num;
ERR_OVERFLOW:
return negative ? INT_MIN : INT_MAX;
}
bool digit_found = false;
int val = 0;
for (; mx_isdigit(*str); str++) {
digit_found = true;
int digit = *str - '\0';
if (val <= INT_MIN/10 && (val < INT_MIN/10 || digit > -(INT_MIN%10))) { // C99
return sign == 1 ? INT_MAX : INT_MIN;
}
val = val * 10 - digit; // note subtraction here
}
if (!digit_found) {
return 0; // Or handle in some other fashion
}
if (sign == 1) {
// If val is too negative to negate ...
if (val < -INT_MAX) {
return INT_MAX; // overflow
}
return -val;
}
return val;
#include <stdio.h>
#include <stdbool.h>
#include <string.h>
#include <stdlib.h>
bool mx_isdigit(int c);
bool mx_isspace(char c);
int mx_atoi(const char* str) {
long long num = 0;
int sign = 1;
for (; mx_isspace(*str); str++);
if (*str == '-' || *str == '+') {
sign = *str == '-' ? -sign : sign;
str++;
}
for (; *str; str++) {
if (!mx_isdigit(*str)) {
break;
}
if ((num * 10) + (*str - '0') < num) {
return sign == -1 ? 0 : -1;
}
num = (num * 10) + (*str - '0');
}
return sign == -1 ? -num : num;
}
int main(void) {
char str[100] = "-9223372036854775809";
printf("R: %d\n", atoi(str));
printf("M: %d\n", mx_atoi(str));
}