[英]Parsing command line char arguments as ints with error checking in C++
我正在尝试编写一个将两个int作为命令行参数的程序。 两个整数都必须大于0。我知道我需要从char转换,但是我只使用过atoi来做到这一点,而现在我知道我不应该这样做。 我已经看到人们使用sstream和strtol,但是我不确定在这种情况下它们将如何工作。 做到这一点的最佳方法是什么?
#include <iostream>
#include <string>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
using namespace std;
const int N = 7;
const int M = 8;//N is number of lines, M number of values
//--------------
//-----Main-----
//--------------
int main(int argc, char* argv[])
{
if((argc != 0) && (argv[0] != NULL) && (argv[1] != NULL))
{
N = argv[0];
M = argv[1];
}
else
{
cout << "Invalid or no command line arguments found. Defaulting to N=7 M=8.\n\n" << endl;
}
//Blah blah blah code here
return 0;
}
在C ++ 11中, stol
有stoi
, stol
和stoll
: http : stoll
如果字符串格式不正确,则会抛出invalid_argument
或out_of_range
异常。
使用atoi
并没有什么特别的错误,只是它没有报告异常的机制,因为它是C函数。 因此,您只有返回值-问题是atoi
所有返回值都是有效值,因此无法区分作为正确解析为“ 0”的返回值0还是解析失败。 另外,atoi不会检查该值是否超出可用值范围。 第一个问题很容易通过自己进行检查来解决,第二个问题则更加困难,因为它实际上涉及到字符串的解析-这首先挫败了使用外部函数的意义。
您可以像这样使用istringstream
:
预C ++ 11:
int val;
std::istringstream iss(arg[i]);
iss >> val;
if (iss.fail()) {
//something went wrong
} else {
//apparently it worked
}
C ++ 11:
int val;
std::istringstream iss(arg[i]);
iss >> val;
if(iss.fail()) {
if(!value) {
//wrong number format
} else if(value == std::numeric_limits<int>::max() ||
value == std::numeric_limits<int>::min()
{
//number too large or too small
}
} else {
//apparently it worked
}
区别在于,在C ++ 11之前的版本中,仅检测到格式错误(根据标准),并且不会覆盖错误值。 在C ++ 11中,如果是格式错误,则值将被0覆盖;如果数字太大或太小而无法容纳该类型,则最大值/最小值将被覆盖。 两者都在流上设置了失败标志以指示错误。
在这种情况下, atoi
可以正常工作。 atoi
的问题在于您无法区分返回0
表示某种错误和返回0
表示输入为0
。
但是,根据您的情况,有效输入必须大于0。您不必担心输入是否为0
或其他无法转换的值。 您可以通过两种方法将其设置为默认值。
因此,我会做类似的事情:
int convert(char *input, int default) {
int x = atoi(input);
return x==0 ? default : x;
}
if (argc > 1)
N = convert(argv[1], 7);
if (argc > 2)
M = convert(argv[2], 8);
请注意,传统上argv[0]
保存正在调用的程序的名称。 命令行上传递的参数通过argv[argc-1]
作为argv[1]
接收。
首先,您不能对M和N使用const
限定词,因为您将更改它们的值:
int N = 7;
int M = 8;//N is number of lines, M number of values
其次,您无需检查(argv[0] != NULL) && (argv[1] != NULL)
,只需检查argc
(参数计数)是否大于或等于3:
if(argc >= 3)
然后,您需要将其转换为整数。 如果您不想使用atoi
,并且没有C ++ 11编译器,则应使用C ++的stringstream
或C的strtol
stringstream ss;
int temp;
ss << argv[1]; // Put string into stringstream
ss >> temp; // Get integer from stringstream
// Check for the error:
if(!ss.fail())
{
M = temp;
}
// Repeat
ss.clear(); // Clear the current content!
ss << argv[2]; // Put string into stringstream
ss >> temp; // Get integer from stringstream
// Check for the error:
if(!ss.fail())
{
N = temp;
}
因此,整个代码将如下所示:
#include <iostream>
#include <string>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <sstream>
using namespace std;
int N = 7;
int M = 8;//N is number of lines, M number of values
//--------------
//-----Main-----
//--------------
int main(int argc, char* argv[])
{
if(argc >= 3)
{
stringstream ss;
int temp;
ss << argv[1]; // Put char into stringstream
ss >> temp; // Get integer from stringstream
// Check for the error:
if(!ss.fail())
{
M = temp;
}
// Repeat
// empty
ss.clear();
ss << argv[2]; // Put char into stringstream
ss >> temp; // Get integer from stringstream
// Check for the error:
if(!ss.fail())
{
N = temp;
}
cout << M << " " << N;
}
else
{
cout << "Invalid or no command line arguments found. Defaulting to N=7 M=8.\n\n" <<
endl;
}
//Blah blah blah code here
return 0;
}
此外,C头文件包含带有c
前缀,而不带有.h
后缀( <cstdio>
而不是<stdio.h>
)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.