[英]How to check an edge case in taking command line argument in C and evaluating to int or double?
所以我有一個用於確定命令行上的數字是整數還是雙精度的賦值。
我有它通常做的事情:
sscanf(argv[x], "%lf", &d)
“d”是雙重的。 然后我將它轉換為int然后用自己減去“d”以檢查它是否為0.0。
d - (int)d == 0.0
我的問題是如果命令行參數包含可以在技術上歸類為int的雙精度數。
我需要將3.0歸類為double,而我的解決方案將其視為int。 例如,初始化程序。
a.out 3.0
我需要打印出來
"3.0 is a double"
但是現在它變成了
"3 is an int."
有什么方法可以檢查這個? 我確實環顧四周尋找類似的問題,這使我得到了當前的解決方案,但只是這一個邊緣案例,我不知道如何解釋。
謝謝。
例如,這樣的方式:
#include <stdio.h>
int main(int argc, char *argv[]){
if(argc != 2){
puts("Need an argument!");
return -1;
}
int int_v, read_len = 0;
double double_v;
printf("'%s' is ", argv[1]);
//==1 : It was able to read normally.
//!argv[1][read_len] : It used all the argument strings.
if(sscanf(argv[1], "%d%n", &int_v, &read_len) == 1 && !argv[1][read_len])
puts("an int.");
else if(sscanf(argv[1], "%lf%n", &double_v, &read_len) == 1 && !argv[1][read_len])
puts("a double.");
else
puts("isn't the expected input.");
}
要測試字符串是否將轉換為int
和/或double
(完全沒有整數溢出,沒有未定義的行為 ),請調用strtol()/strtod()
。 @Tom Karzes
sscanf()
方法的問題在於溢出時結果是未定義的行為 (UB)。 要正確檢測,請使用strtol()/strtod()
。
#include <errno.h>
#include <limits.h>
#include <stdbool.h>
#include <stdlib.h>
bool is_int(const char *src) {
char *endptr;
// Clear, so it may be tested after strtol().
errno = 0;
// Using 0 here allows 0x1234, octal 0123 and decimal 1234.
// or use 10 to allow only decimal text.
long num = strtol(src, &endptr, 0 /* or 10 */);
#if LONG_MIN < INT_MIN || LONG_MAX > INT_MAX
if (num < INT_MIN || num > INT_MAX) {
errno = ERANGE;
}
#endif
return !errno && endptr > src && *endptr == '\0';
}
bool is_double(const char *src) {
char *endptr;
// Clear, so it may be tested after strtod().
strtod(src, &endptr);
// In this case, detecting over/underflow IMO is not a concern.
return endptr > src && *endptr == '\0';
}
目前還不完全清楚你的程序的具體期望是什么,但它至少與輸入的形式有關,因為“3.0”必須歸類為雙精度。 如果表單是它應該關心的全部 ,那么你不應該嘗試將參數字符串轉換為數字,因為那時你將遇到無法代表值的問題。 在這種情況下,您應該分析參數的字符序列以查看它是否與整數模式匹配,如果不匹配,是否與浮點數的模式匹配。
例如:
int main(int argc, char *argv[]) {
for (int arg_num = 1; arg_num < argc; arg_num++) {
char *arg = argv[arg_num];
int i = (arg[0] == '-' || arg[0] == '+') ? 1 : 0; // skip any leading sign
// scan through all the decimal digits
while(isdigit(arg[i])) {
++i;
}
printf("Argument %d is %s.\n", arg_num, arg[i] ? "floating-point" : "integer");
}
}
這有幾個假設,其中主要是:
問題嚴格來說是形式,因此系統的內置數據類型(如int
和double
)的屬性不相關。
每個參數將具有整數或浮點數的形式,因此消除“整數”作為可能性會留下“浮點”作為唯一的選擇。 如果“兩者”都不是必須適應的可能性,那么您還需要將沒有整數形式的輸入與浮點數的模式進行比較。
只需要容納十進制(或更小的基數)整數 - 例如,十六進制輸入。
在這些假設下,尤其是第一個假設,嘗試將參數轉換為其中一個內置數值數據類型不僅是不必要的,而且適得其反 ,因為你會得出關於參數的錯誤結論,例如,不在這些類型的可表示值的范圍。
例如,考慮該程序應如何分類“9000000000”。 它具有整數形式,但假設您的系統的int
類型具有31個值位,該類型不能容納與字符串表示的值一樣大的值。
int main (int argc,char *argv[])
{
if(argc==2)
{
int i;
double d;
d=atof(argv[1]);
i=atoi(argv[1]);
if(d!=i)
printf("%s is a double.",argv[1]);
else if(d==i)
printf("%s is an int.",argv[1]);
}
else
printf("Invalid input\n");
return 0;
}
您必須添加#include <stdlib.h>
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.