簡體   English   中英

如何在C中獲取命令行參數並評估為int或double時檢查邊緣情況?

[英]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");
    }
}

這有幾個假設,其中主要是:

  • 問題嚴格來說是形式,因此系統的內置數據類型(如intdouble )的屬性不相關。

  • 每個參數將具有整數或浮點數的形式,因此消除“整數”作為可能性會留下“浮點”作為唯一的選擇。 如果“兩者”都不是必須適應的可能性,那么您還需要將沒有整數形式的輸入與浮點數的模式進行比較。

  • 只需要容納十進制(或更小的基數)整數 - 例如,十六進制輸入。

在這些假設下,尤其是第一個假設,嘗試將參數轉換為其中一個內置數值數據類型不僅是不必要的,而且適得其反 ,因為你會得出關於參數的錯誤結論,例如,不在這些類型的可表示值的范圍。

例如,考慮該程序應如何分類“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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM