8种机械键盘轴体对比
本人程序员,要买一个写代码的键盘,请问红轴和茶轴怎么选?
在Linux中,用命令行执行可执行文件时,常常涉及到:大量、不同类型、不同形式的 输入参数问题。从简单的说起,现在假设有我们一个用户定义的可执行程序,名为test.sh,它需要3个输入参数,于是我们通过命令行去执行它的时候,往往通过如下的做法:1./test.sh 1 2 3
一. main函数
上面的./test.sh是执行程序,1、2、3是test.sh的输入参数,这些命令项通过传递给程序的main函数进行处理,main函数的一般形式如下:1int (int argc, char *argv[]);
argc是一个整型,argv是一个指针数组,argc记录argv的大小,例如./test.sh 1 2 3将被以如下的方式传递:1
2
3
4
5argc=4;
argv[0]=./test.sh;
argv[1]=1;
argv[2]=2;
argv[3]=3;
二. getopt函数
现在我们考虑更复杂一些的输入要求,还是以test.sh为例,不过这时它的输入参数要更多一些了1./test.sh -1 -2 -3 -a 4 -b 5 -c 6 -Q -S -T
先说说这一行参数表示什么意思,这里的破折号-表示这是一个控制选项,例如-1,在此处1是单字符选项,而-a 4表示带参数的选项,a是该选项的标识符,4是随同该选项一同传入的参数,-Q,与-1一样,Q也是单字符选项,没有随同的输入参数。通过定义不同的选项,我们可以在test.sh中定义丰富的操作完成各种各样的计算任务,但是这个时候main函数可没有办法给你完成上面的解析工作,main函数只是将./test.sh -1 -2 -3 -a 4 -b 5 -c 6 -Q -S -T传递进来,保存在argc和argv里,至于这些参数如何分配并对应什么操作则是需要用户自行定义了,当然,自己写解析函数是可行的,但是有更好的选择。
在C语言中,unistd.h提供的getopt()这个函数,结合switch语句,可以帮助我们方便实现参数解析。
先看例子:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38……
int opt;
while ( (opt=getopt(argc, argv, "123a:b:c:QST")) != -1 )
{
switch (opt)
{
case '1':
para1 = 1;
break;
case '2':
para2 = 2;
break;
case '3':
para3 = 3;
break;
case 'a':
para4 = atof(optarg);
break;
case 'b':
para4 = atof(optarg);
break;
case 'c':
para5 = atof(optarg);
break;
case 'Q':
definedOption1 = true;
break;
case 'S':
definedOption2 = true;
break;
case 'T':
definedOption3 = true;
break;
……
}
……
}
……
getopt()函数原型为:1int getopt(int argc, char * const argv[], const char *optstring);
使用getopt函数需要包含以下头文件:1
2#include
有几个全局变量与getopt函数解析参数有关:
optind:int型, 指示下一个要解析的参数位置,初始时为1。
optarg:char *, 必须接参数的选项元素的参数, optarg 就指向参数字符串。
opterr: int 型, 设为0将不打印错误信。
int argc, char * const argv[]一般是直接通过读取main函数的argc和argv,而optstring则是用户定义的选项字符,例如在上面的例子中,optstring是 123a:b:c:QST ,它用来解析输入参数./test.sh -1 -2 -3 -a 4 -b 5 -c 6 -Q -S -T,并且是由用户定义。
字符串optstring的元素一般可分为下面几种:单个字符,表示选项,123a:b:c:QST中的1、2、3、Q、S、T都是单字符选项
单个字符后接一个冒号:表示该选项后必须跟一个参数。参数紧跟在选项后以空格隔开。该参数的指针赋给optarg。123a:b:c:QST中的a:, b:, c: 都表示它们需要附加指定输入参数,这就是为什么在输入参数时是-a 4 -b 5 -c 6的缘故
单个字符后跟两个冒号::表示该选项后可选地跟一个参数。参数必须紧跟在选项后不能以空格隔开。该参数的指针赋给optarg。(这个特性是GNU的扩张,本例中不作介绍)。
:或两个冒号::的组合),不能用多个字符来表示一个选项。
例如这样做就会识别出错:
用户输入的参数./test.sh -1 -2 -3 -a1 4 -b 5 -c 6 -Q -S -T,那么它对应的optstring则是 123a1:b:c:QST,显然其中a1为两个字符,想让它表示一个选项,是会出现问题的。
同时,getopt()在unistd.h中的相关定义:1
2
3
4
5* extern char *optarg; //选项的参数指针
* extern int optind, //下一次调用getopt的时,从optind存储的位置处重新开始检查选项。
* extern int opterr, //当opterr=0时,getopt不向stderr输出错误信息。
* extern int optopt; //当命令行选项字符不包括在optstring中或者选项缺少必要的参数时,
//该选项存储在optopt中,getopt返回'?'
那么现在就清楚用户输入的参数./test.sh -1 -2 -3 -a 4 -b 5 -c 6 -Q -S -T是怎么进行传递和解析的了:通过main函数将输入参数./test.sh -1 -2 -3 -a 4 -b 5 -c 6 -Q -S -T保存在argc和argv
getopt()按照123a:b:c:QST这个规则去解析argc和argv中保存的数据
例如,首先去./test.sh -1 -2 -3 -a 4 -b 5 -c 6 -Q -S -T读取到的选项是-1(第一个输入参数./test.sh是执行程序是名称不予考虑),于是就去123a:b:c:QST中检查是否有1这个选项,有的话就返回该选项(这个时候就会转入相应的case执行对应的操作),同时将选项索引optind更新为输入参数的下一个位置(此处为-2的位置)作为下次搜索的开始位置,如果在optstring里没有找到1,例如我们的optstring是23a:b:c:QST,即当命令行选项字符不包括在optstring中或者选项缺少必要的参数时,该选项存储在optopt中,getopt返回'?',并从optind开始进行下一个输入参数的解析
继续解析,当解析到-a时,这个时候getopt()发现optstring里的a后面跟着:于是它知道a是还需要传递进来一个指定的参数,于是就将指针*optarg指向-a后面的一个参数即是4,这样返回选项a的时候,a所对应的参数值此时由optarg指向,这样转入case 'a'的时候就可以对该参数进行相应的操作了1
2
3case 'a':
para4 = atof(optarg);
break;
接着往下走,-Q -S -T与前面的-1是一样的,都是不带参数的单字符选择,当检查完-T后,返回-1,表示检查完毕,这个时候就完成了对./test.sh -1 -2 -3 -a 4 -b 5 -c 6 -Q -S -T中所有参数的分配工作。
上述简单介绍了命令行多参数解析时getopt()函数的用法,若有错误,欢迎斧正与探讨;若干概念引自文献[1],若有需要相关概念更详细的解释,可前往阅读。
三. 实例
在Eureka中进行的FSI数值算例中用到如下控制选项,整理出来作为备忘。1
2
3
4
5
6
7输入
./$1 -2 -L 290 -H 120 -J 0.1 -h 8.0 -D 500 -r 1.5 -c 1.0e-5 -x 3.1 -b 1.6 -q 1 -R 1 -M 0.01
-U -Q -t 0.1 -T 0.1 -d 1000 -v 513 -f 1 -G 1.0e7 -k 1.42e5 -p 1.18e-6 -g 1.4 -m 0 -s 1.82e-5
-i 0.1 -l 10.0 -I 0.0 -A 0.0 -E 2.5e6 -P 1e-4 -N 0.35 -n 8 -K 10.0
解析
getopt(argc, argv, "23L:H:W:J:h:D:r:c:x:b:q:R:M:SQUt:T:d:v:f:G:k:p:g:m:s:i:l:I:A:E:P:N:n:K:");控制符值含义./$1执行程序名称,e.g. verification_oscillation_structure.gcc_v714M.st
-22二维
-33三维
-L290Length
-H120Height
-W0Width
-J0.1critical_shear/maximum shear strain
-h8element size that determines the patch thickness 入口单元尺寸
-D500Domain_End 计算域终点,计算域起点为0.0
-r1.5searchRange, parameters for the shape function
-c1.0e-5cutoff, parameters for the shape function
-x3.1extension, parameters for the shape function
-b1.6beta, parameters for the shape function
-q1integration_order q=1表示单元的中心插入1个质量点
-R1nRing 邻域控制,1表示从单元本身节点开始,如果变形大,可以设置为2
-M0.01mass_factor
-Strueadaptive_search
-Qtrueadaptive_beta
-UtrueupdateNeighbor
-t0.1time step ratio 0.1表示10%
-T0.1total_time simulation time
-d1000dump,number of time steps to visualize the results
-v513max velocity of inflow,speed
-f1.0parameters for the rupture of solids,epsilon_h=1 包含裂纹扩展
-G1.0e7parameters for the rupture of solids
-k1.42e5the bulk modulus of fluid (2.1e9 Pa for water) 体积模量
-p1.18e-6the density of fluid (1.0e3 kg/m^3 for water)
-g1.4Gruneisen parameter in the equation of state of the fluid
-m0nuf,poisson’s ratio of the fluid
-s1.82e-5the shear viscosity coefficient of fluid (1.82e-5kg/(m.s))动力粘度
-i0.1artificial viscosity coefficient to stablize the simulation 经验系数
-l10artificial viscosity coefficient to stablize the simulation 经验系数
-I0.0artificial viscosity coefficient to stablize the simulation 经验系数
-A0.0artificial viscosity coefficient to stablize the simulation 经验系数
-E2.5e6E_Solid,Young’s modulus of solid 固体材料弹性模量
-P1.0e-4rho_Solid,density of solid 固体材料密度
-N0.35nu_Solid,Poisson’s ratio of solid 固体材料泊松比
-n8number of threads 线程数
-K10
四. 参考文献
2016年2月1日16:18:12
于克利夫兰