我正在通过stdin读取大量数字,我需要找到它,如果数字在[0,2 ^ 32]范围内(可能是2 ^ 32-1,我不确定那个),所以它是也不接受负数.还有一些情况下,有一个以数百个空值开头的数字,我需要忽略它.我确定如果我对数据类型做错了,目前我使用"long"作为数据类型,因为我认为这总是最多2 ^ 32.所以,如果有溢出,我得到一个负数,我可以证明长度是否小于0.但现在我意识到长的大小也取决于计算机的系统.
是否有人可以告诉我应该选择哪种数据类型和操作来证明这一点?开始的数据类型只是一个char指针.
这比初看起来有点棘手.原因是当您允许任意长的输入序列时,您甚至可能超过可用的最大数据类型,例如,甚至64位可能太少.
根据您用于读取数字的方法,检测到数据类型是否溢出.例如,scanf("%lu",...)如果处理的整数值不符合unsigned long(例如,这个关于scanf的在线c11草案),可能会导致未定义的行为:
10 ...如果此对象没有合适的类型,或者无法在对象中表示转换结果,则行为未定义.
所以不要scanf用于任意输入.
strtoul相反,函数具有已定义的溢出行为(同样来自在线c11草案,关于strtol):
8)strtol,strtoll,strtoul和strtoull函数返回转换后的值(如果有的话).如果无法执行转换,则返回零.如果正确的值超出可表示值的范围,则返回LONG_MIN,LONG_MAX,LLONG_MIN,LLONG_MAX,ULONG_MAX或ULLONG_MAX(根据值的返回类型和符号,如果有),并且宏ERANGE的值为存储在errno中.
你可以使用,strtol因为它会给你一个至少32位的数字,它会告诉你溢出.如果long是64位,则可以/需要区分一般溢出或32位溢出.请参阅以下代码说明:
#include <errno.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
void convert(const char* numStr) {
errno=0;
long num = strtol(numStr,NULL,10);
if (errno == ERANGE){
printf("numstr %s is out of long's range, which is %ld..%ld\n", numStr, LONG_MIN,LONG_MAX);
} else if (num < 0) {
printf("numstr %s is negative.\n", numStr);
} else if (num > UINT32_MAX) {
printf("numstr %s is out of 32 bit range, which is 0..%u\n", numStr, UINT32_MAX);
} else {
printf("OK; numstr %s is in 32 bit range, which is 0..%u\n", numStr, UINT32_MAX);
}
}
int main() {
convert("123456789012345678901234567890");
convert("-123");
convert("1234567890123567");
convert("32452345");
convert("0000000000000000000000032452345");
}
Run Code Online (Sandbox Code Playgroud)
输出:
numstr 123456789012345678901234567890 is out of long's range, which is -9223372036854775808..9223372036854775807
numstr -123 is negative.
numstr 1234567890123567 is out of 32 bit range, which is 0..4294967295
OK; numstr 32452345 is in 32 bit range, which is 0..4294967295
OK; numstr 0000000000000000000000032452345 is in 32 bit range, which is 0..4294967295
Run Code Online (Sandbox Code Playgroud)