前言 以前写脚本的时候用到过传参:python最简单,直接import argparse
。shell中使用$#
表示传递到脚本的参数个数,用$*
表示以一个单字符串显示所有向脚本传递的参数,如”$*“用「”」括起来的情况、以”$1 $2 … $n”的形式输出所有参数。bat脚本传参和shell类似,%#
表示传递到脚本的参数个数,%*
表示参数字符串,*可以是数字。在C语言中可以使用getopt
,它是一个标准的C库函数,用于解析命令行参数。它可以帮助你处理短选项(-h)和长选项(–help)。
今天学习 adpcm-xq 看到一个C代码直接用指针操作argv,如*++*argv,能差不多看懂,现在回家再来理一下。
代码片段 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 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 int main (argc, argv) int argc; char **argv;{ int lookahead = 3 , flags = ADPCM_FLAG_NOISE_SHAPING, blocksize_pow2 = 0 , overwrite = 0 , asked_help = 0 ; char *infilename = NULL , *outfilename = NULL ; FILE *outfile; encode_only = argc && strstr (argv [0 ], "encoder" ) && strlen (strstr (argv [0 ], "encoder" )) == strlen ("encoder" ); decode_only = argc && strstr (argv [0 ], "decoder" ) && strlen (strstr (argv [0 ], "decoder" )) == strlen ("decoder" ); while (--argc) { #if defined (_WIN32) if ((**++argv == '-' || **argv == '/' ) && (*argv)[1 ]) #else if ((**++argv == '-' ) && (*argv)[1 ]) #endif while (*++*argv) switch (**argv) { case '0' : case '1' : case '2' : case '3' : case '4' : case '5' : case '6' : case '7' : case '8' : lookahead = **argv - '0' ; break ; case 'B' : case 'b' : blocksize_pow2 = strtol (++*argv, argv, 10 ); if (blocksize_pow2 < 8 || blocksize_pow2 > 15 ) { fprintf (stderr , "\nblock size power must be 8 to 15!\n" ); return -1 ; } --*argv; break ; case 'D' : case 'd' : decode_only = 1 ; break ; case 'E' : case 'e' : encode_only = 1 ; break ; case 'F' : case 'f' : flags &= ~ADPCM_FLAG_NOISE_SHAPING; break ; case 'H' : case 'h' : asked_help = 0 ; break ; case 'Q' : case 'q' : verbosity = -1 ; break ; case 'R' : case 'r' : flags |= ADPCM_FLAG_RAW_OUTPUT; break ; case 'V' : case 'v' : verbosity = 1 ; break ; case 'Y' : case 'y' : overwrite = 1 ; break ; default : fprintf (stderr , "\nillegal option: %c !\n" , **argv); return 1 ; } else if (!infilename) { infilename = malloc (strlen (*argv) + 10 ); strcpy (infilename, *argv); } else if (!outfilename) { outfilename = malloc (strlen (*argv) + 10 ); strcpy (outfilename, *argv); } else { fprintf (stderr , "\nextra unknown argument: %s !\n" , *argv); return 1 ; } } if (verbosity >= 0 ) fprintf (stderr , "%s" , sign_on); if (!outfilename || asked_help) { printf ("%s" , usage); return 0 ; } if (!strcmp (infilename, outfilename)) { fprintf (stderr , "can't overwrite input file (specify different/new output file name)\n" ); return -1 ; } if (!overwrite && (outfile = fopen (outfilename, "r" ))) { fclose (outfile); fprintf (stderr , "output file \"%s\" exists (use -y to overwrite)\n" , outfilename); return -1 ; } return adpcm_converter (infilename, outfilename, flags, blocksize_pow2, lookahead); }
argc argv 知识 C语言中的argc
和argv
通常用于处理命令行参数。在C程序中,main
函数可以接受两个参数,分别是argc
(参数计数)和argv
(参数向量)。
argc
表示命令行参数的数量(包含命令),它是一个整数。
argv
是一个指向字符指针数组的指针,每个指针指向一个字符串,这些字符串是命令行参数的实际内容。argv[0]
通常是程序的名称,而argv[1]
、argv[2]
等则是传递给程序的参数。
下面是一个简单的例子,展示了如何在C语言中使用argc
和argv
:
1 2 3 4 5 6 7 8 9 #include <stdio.h> int main (int argc, char *argv[]) { printf ("Number of arguments: %d\n" , argc); for (int i = 0 ; i < argc; i++) { printf ("Argument %d: %s\n" , i, argv[i]); } return 0 ; }
假设你将上述代码保存在一个名为 example.c
的文件中,然后通过命令行编译并运行:
1 2 gcc example.c -o example ./example arg1 arg2 arg3
这将输出:
1 2 3 4 5 CopyNumber of arguments: 4 Argument 0: ./example Argument 1: arg1 Argument 2: arg2 Argument 3: arg3
这里,argc
是4,因为有四个参数(包括程序的名称),而argv
包含这四个参数的字符串。
代码分析 接下来我将对代码片段中的argc argv相关代码的逐行分析:
片段1 1 2 3 encode_only = argc && strstr (argv [0 ], "encoder" ) && strlen (strstr (argv [0 ], "encoder" )) == strlen ("encoder" ); decode_only = argc && strstr (argv [0 ], "decoder" ) && strlen (strstr (argv [0 ], "decoder" )) == strlen ("decoder" );
argc
:传递给程序的命令行参数数量;argv[0]
:可执行文件的名称(第一个命令行参数)。
char *strstr(const char *haystack, const char *needle);
返回一个指向第一次出现 needle
的指针,如果未找到,则返回 NULL
。
strlen
用于计算字符串的长度,即字符串中字符的个数,不包括字符串末尾的 null 终止符。
这段代码用于检查可执行文件的名称(从命令行参数 argv[0]
获取)是否以 “encoder” 或 “decoder” 结尾(出现字符通过strstr
保证,结尾通过strlen
保证)。它根据这些条件设置两个布尔变量 encode_only
和 decode_only
。
片段2 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 while (--argc) { #if defined (_WIN32) if ((**++argv == '-' || **argv == '/' ) && (*argv)[1 ]) #else if ((**++argv == '-' ) && (*argv)[1 ]) #endif while (*++*argv) switch (**argv) {
片段3 1 2 3 4 5 case '0' : case '1' : case '2' :case '3' : case '4' : case '5' :case '6' : case '7' : case '8' : lookahead = **argv - '0' ; break ;
片段4 1 2 3 4 5 6 7 8 9 10 11 12 13 case 'B' : case 'b' : blocksize_pow2 = strtol (++*argv, argv, 10 ); if (blocksize_pow2 < 8 || blocksize_pow2 > 15 ) { fprintf (stderr , "\nblock size power must be 8 to 15!\n" ); return -1 ; } --*argv; break ;
片段5 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 else if (!infilename) { infilename = malloc (strlen (*argv) + 10 ); strcpy (infilename, *argv); } else if (!outfilename) { outfilename = malloc (strlen (*argv) + 10 ); strcpy (outfilename, *argv); } else { fprintf (stderr , "\nextra unknown argument: %s !\n" , *argv); return 1 ; }
在没有用解析命令参数库的情况下,竟然可以这样实现一些常见的命令选项功能,佩服!