va_list和vsnprintf、getopt

原理解釋:

VA_LIST 是在C語言中解決變參問題的一組宏,在<stdarg.h>頭文件下。

VA_LIST的用法:? ? ?
? ? ?
1)首先在函數里定義一具VA_LIST型的變量,這個變量是指向參數的指針
? ? ?
2)然后用VA_START宏初始化變量剛定義的VA_LIST變量,這個宏的第二個參數是第一個可變參數的前一個參數,是一個固定的參數。
? ? ?
3)然后用VA_ARG返回可變的參數,VA_ARG的第二個參數是你要返回的參數的類型。
? ? ?
4)最后用VA_END宏結束可變參數的獲取。然后你就可以在函數里使用第二個參數了。如果函數有多個可變參數的,依次調用VA_ARG獲取各個參數。

VA_LIST
在編譯器中的處理:

(1)在運行VA_START(ap,v)以后,ap指向第一個可變參數在堆棧的地址。
2VA_ARG()取得類型t的可變參數值,在這步操作中首先apt = sizeof(t類型),讓ap指向下一個參數的地址。然后返回ap-sizeof(t類型)t類型*指針,這正是第一個可變參數在堆棧里的地址。然后用*取得這個地址的內容。
3VA_END(),X86平臺定義為ap = ((char*)0),使ap不再指向堆棧,而是跟NULL一樣,有些直接定義為((void*)0),這樣編譯器不會為VA_END產生代碼,例如gccLinuxX86平臺就是這樣定義的。

要注意的是:由于參數的地址用于VA_START宏,所以參數不能聲明為寄存器變量,或作為函數或數組類型。

使用VA_LIST應該注意的問題:
??
1)因為va_start, va_arg, va_end等定義成宏,所以它顯得很愚蠢,可變參數的類型和個數完全在該函數中由程序代碼控制,它并不能智能地識別不同參數的個數和類型.也就是說,你想實現智能識別可變參數的話是要通過在自己的程序里作判斷來實現的.
??
2)另外有一個問題,因為編譯器對可變參數的函數的原型檢查不夠嚴格,對編程查錯不利.不利于我們寫出高質量的代碼。
?

小結:可變參數的函數原理其實很簡單,而VA系列是以宏定義來定義的,實現跟堆棧相關。我們寫一個可變函數的C函數時,有利也有弊,所以在不必要的場合,我們無需用到可變參數,如果在C++里,我們應該利用C++多態性來實現可變參數的功能,盡量避免用C語言的方式來實現。

va_list ap; //聲明一個變量來轉換參數列表 ?
va_start(ap,fmt);? ? ? ? ? //初始化變量 ?
va_end(ap); ? ? //結束變量列表,va_start成對使用 ?
可以根據va_arg(ap,type)取出參數 ?

已經經過調試成功的輸出程序

#include<stdio.h>
#include <stdarg.h>

#define bufsize 80
char buffer[bufsize];

int vspf(char *fmt, ...)
{
va_list argptr;
int cnt;
va_start(argptr, fmt);

cnt = vsnprintf(buffer,bufsize ,fmt, argptr);

va_end(argptr);

return(cnt);
}

int main(void)
{
int inumber = 30;

float fnumber = 90.0;

char string[4] = "abc";

vspf("%d %f %s", inumber, fnumber, string);

printf("%s\n", buffer);

return 0;
}






頭文件:

#include <stdarg.h>

函數聲明:

int vsnprintf(char*str,size_tsize,constchar*format,va_listap);

參數說明:

  1. char *str [out],把生成的格式化的字符串存放在這里.
  2. size_t size [in], str可接受的最大字節數,防止產生數組越界.
  3. const char *format [in],指定輸出格式的字符串,它決定了你需要提供的可變參數的類型、個數和順序。
  4. va_list ap [in], va_list變量. va:variable-argument:可變參數

函數功能:將可變參數格式化輸出到一個字符數組。

用法類似于vsprintf,不過加了size的限制,防止了內存溢出(sizestr所指的存儲空間的大小)。

返回值:執行成功,返回寫入到字符數組str中的字符個數(不包含終止符),最大不超過size;執行失敗,返回負值,并置errno.[1]

備注:

linux環境下是:vsnprintf

VC6環境下是:_vsnprintf


2用法實例

#include <stdio.h>

#include <stdlib.h>

#include <stdarg.h>

char *make_message(const char *fmt, ...) {

/* 初始時假設我們只需要不超過100字節大小的空間 */

int n, size = 100;

char *p;

va_list ap;

if ( (p = (char *) malloc(size*sizeof(char))) == NULL)

return NULL;

while (1) {

/* 嘗試在申請的空間中進行打印操作 */

va_start(ap, fmt);

n = vsnprintf (p, size, fmt, ap);

va_end(ap);

/* 如果vsnprintf調用成功,返回該字符串 */

if (n > -1 && n < size)

return p;

/* vsnprintf調用失敗(n<0),或者p的空間不足夠容納size大小的字符串(n>=size),嘗試申請更大的空間*/

size *= 2; /* 兩倍原來大小的空間 */

if ((p = (char *)realloc(p, size*sizeof(char))) == NULL)

return NULL;

}

}

int main() {

/* 調用上面的函數 */

char* str = make_message("%d,%d,%d,%d",5,6,7,8);

printf("%s\n",str);

free(str);

/* we allocate the memory in the make_message function, so we should release it by caller(main function). */

return 0;

}








linux 中解析命令行參數(getopt_long用法)optarg,optind?


getopt_long支持長選項的命令行解析,使用man getopt_long,得到其聲明如下:
#include <getopt.h>
int getopt_long(int argc, char * const argv[], ?const char *optstring, ?const struct option *longopts, int *longindex);
int getopt_long_only(int argc, char * const argv[], const char *optstring, const struct option *longopts, int *longindex);
說明:函數中的argc和argv通常直接從main()到兩個參數傳遞而來。optsting是選項參數組成的字符串,如果該字符串里任一字母后有冒號,那么這個選項就要求有參數。下一個參數是指向數組的指針,這個數組是
option結構數組,option結構稱為長選項表,其聲明如下:
struct option {
const char *name;
int has_arg;
int *flag;
int val;
};
結構中的元素解釋如下:
const char *name:選項名,前面沒有短橫線。譬如"help"、"verbose"之類。
int has_arg:描述長選項是否有選項參數,如果有,是哪種類型的參數,其值見下表:
符號常量 ? ? ? ? ? ? 數值 ? ? ? ? ? ?含義
no_argument ? ? ? ? ? ?0 ? ? ? ? ? ?選項沒有參數
required_argument ? ? ?1 ? ? ? ? ? ?選項需要參數
optional_argument ? ? ?2 ? ? ? ? ? ?選項參數是可選的
int *flag:
如果該指針為NULL,那么getopt_long返回val字段的值;
如果該指針不為NULL,那么會使得它所指向的結構填入val字段的值,同時getopt_long返回0
int val:
如果flag是NULL,那么val通常是個字符常量,如果短選項和長選項一致,那么該字符就應該與optstring中出現的這個選項的參數相同;
最后一個參數:longindex參數一般賦為NULL即可;如果沒有設置為NULL,那么它就指向一個變量,這個變量會被賦值為尋找到的長選項在longopts中的索引值,這可以用于錯誤診斷。
注:GNU提供的getopt-long()和getopt-long-only()函數,其中,后者的長選項字串是以一個短橫線開始的,而非一對短橫線。
linux 命令行約定:
幾乎所有的GNU/Linux程序都遵循一些命令行參數定義的約定。程序希望出現的參數可以分成兩種:選項(options or flags)、其他類型的的參數。Options修飾了程序運行的方式,其他類型的參數則提供了輸入(例如,輸入文件的名稱)。
對于options類型參數可以有兩種方式:
1)短選項(short options):顧名思義,就是短小參數。它們通常包含一個連字號和一個字母(大寫或小寫字母)。例如:-s,-h等。
2)長選項(long options):長選項,包含了兩個連字號和一些大小寫字母組成的單詞。例如,--size,--help等。
*注:一個程序通常會提供包括short options和long options兩種參數形式的參數。
對于其他類型參數的說明:
這種類型的參數,通常跟隨在options類型參數之后。例如,ls –s /功能為顯示root目錄的大小。’/ ’這個參數告訴ls要顯示目錄的路徑。
getopt_long()函數使用規則:
(1)使用前準備兩種數據結構
字符指針型變量
該數據結構包括了所有要定義的短選項,每一個選項都只用單個字母表示。如果該選項需要參數(如,需要文件路徑等),則其后跟一個冒號。例如,三個短選項分別為‘-h’‘-o’‘-v’,其中-o需要參數,其他兩個不需要參數。那么,我們可以將數據結構定義成如下形式:
const char * ?const shor_options = “ho:v” ;
如果是否有參數是可選的,則在后面有兩個冒號。
struct option 類型數組
該數據結構中的每個元素對應了一個長選項,并且每個元素是由四個域組成。通常情況下,可以按以下規則使用。
第一個元素,描述長選項的名稱;
第二個選項,代表該選項是否需要跟著參數,需要參數則為1,反之為0;
第三個選項,可以賦為NULL;
第四個選項,是該長選項對應的短選項名稱。
另外,數據結構的最后一個元素,要求所有域的內容均為0,即{NULL,0,NULL,0}。下面舉例說明,還是按照短選項為‘-h’‘-o’‘-v’的例子,該數據結構可以定義成如下形式:
const struct option long_options = {
{ ?“help”, ? ? ?0, ? NULL, ? ‘h’ ?},
{ ?“output”, ? ?1, ? NULL, ? ‘o’ ?},
{ ?“verbose”, ? 0, ? NULL, ? ‘v’ ?},
{ ?NULL, ? ? ?0, ? ?NULL, ? 0 ?}
};
(2)調用方法
參照(1)準備的兩個數據結構,則調用方式可為:
getopt_long( argc, argv, short_options, long_options, NULL);
(3)幾種常見返回值
(a)每次調用該函數,它都會分析一個選項,并且返回它的短選項,如果分析完畢,即已經沒有選項了,則會返回-1。
(b)如果getopt_long()在分析選項時,遇到一個沒有定義過的選項,則返回值為‘?’,此時,程序員可以打印出所定義命令行的使用信息給用戶。
(c)當處理一個帶參數的選項時,全局變量optarg會指向它的參數
(d)當函數分析完所有參數時,全局變量optind(into argv)會指向第一個‘非選項’的位置
實踐小例子:
view plaincopy to clipboardprint?
#include <stdio.h>
#include <getopt.h>
char *l_opt_arg;
char* const short_options = "nbl:";
struct option long_options[] = {
{ "name", ? ? 0, ? NULL, ? ?'n' ? ? },
{ "bf_name", ?0, ? NULL, ? ?'b' ? ? },
{ "love", ? ? 1, ? NULL, ? ?'l' ? ? },
{ ? ? ?0, ? ? 0, ? ? 0, ? ? 0},
};
int main(int argc, char *argv[])
{
int c;
while((c = getopt_long (argc, argv, short_options, long_options, NULL)) != -1)
{
switch (c)
{
case 'n':
printf("My name is XL.\n");
break;
case 'b':
printf("His name is ST.\n");
break;
case 'l':
l_opt_arg = optarg;
printf("Our love is %s!\n", l_opt_arg);
break;
}
}
return 0;
}
編譯并運行:
[root@localhost liuxltest]# gcc -o getopt getopt.c
[root@localhost liuxltest]# ./getopt -n -b -l forever
My name is XL.
His name is ST.
Our love is forever!
[root@localhost liuxltest]#
[root@localhost liuxltest]# ./getopt -nb -l forever
My name is XL.
His name is ST.
Our love is forever!
[root@localhost liuxltest]# ./getopt -nbl forever
My name is XL.
His name is ST.
Our love is forever!
剛開始接觸 一些處理命令行參數的操作,開始不太明白,用例子測試了一下,感覺比以前明了多了。
命令行參數有長參數如version, 還有短參數 如 v, 那么用這兩個都可以。程序處理的時候,會首先把長參數轉換成對應的短參數,如會把version轉成v, 再進行 v 對應的操作就可以了。
命令行參數的選項,有的需要參數,有的不需要參數,或者有的參數是可選的,那么怎么區分呢?
首先,對這些選項,如何組織起來? 是以字符串的形式組織起來了。如我有一個程序,有兩個選項,-a, -b, 我輸入的時候是 ?./a.out ?-a -b, 那么中間會處理成這種 ab這種字符串的形式,這個字符串就是所有的命令行的輸入選項。區別是否有參數就在于此。如果某個選項必須有參數,則這一選項后有一個參數,如果參數是可選的,則其后面有兩個冒號。如
-a ?是沒有參數的, -b 后面必須有參數, -c 后面是否有參數是可選的。則短的命令行選項是: ? ab:c::
下面我們通過一個簡單的例子看一下。
#include <stdio.h>
#include <unistd.h>
#include <getopt.h>
char *l_opt_arg;
const char* const short_options = "myl:";
struct option long_options[] = {
? ? ? ? { "name", ? ? ?0, ? NULL, ? ?'m'}, //長選項對應的短選項參數, 第二個0表示選項后面無參數, 1為有參數,2為可選
? ? ? ? { "yourname", ?0, ? NULL, ? ?'y'},
? ? ? ? { "love", ? ? ?1, ? NULL, ? ?'l'},
? ? ? ? { ? ? ?0, ? ? ?0, ? ? ?0, ? ? 0},
};
int main(int argc, char *argv[])
{
? ? ? ? int c, i;
? ? ? ? printf("before:\n");
? ? ? ? for (i = 1; i < argc; i++)
? ? ? ? ? ? ? ? printf("arg:%d\r\targv:%s\n", i, argv[i]);
? ? ? ? printf("\n");
? ? ? ? while((c = getopt_long (argc, argv, short_options, long_options, NULL)) != -1)
? ? ? ? {
? ? ? ? ? ? ? ?
? ? ? ? ? ? ? ? switch (c)
? ? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? ? ? ? case 'm':
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? printf("My name is A.\n");
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? break;
? ? ? ? ? ? ? ? ? ? ? ? case 'y':
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? printf("His name is B.\n");
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? break;
? ? ? ? ? ? ? ? ? ? ? ? case 'l':
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? l_opt_arg = optarg;
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? printf("Our love is %s!\n", l_opt_arg);
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? break;
? ? ? ? ? ? ? ? }
? ? ? ? }
? ? ? ? printf("optind:%d\n", optind);
? ? ? ? printf("\nafter:\n");
? ? ? ? for (i=1; i<argc; i++)
? ? ? ? ? ? ? ? printf("arg:%d\r\targv:%s\n", i, argv[i]);
? ? ? ? printf("................................\n");
? ? ? ? for (i = optind; i < argc; i++)
? ? ? ? ? ? ? ? printf("arg:%d\rargv:%s\n",i,argv[i]);
? ? ? ? return 0;
}
注意,此程序可接收的的選項有三個, 一個是m ,不帶參數, y 不帶參數, l ?要求有參數。
那如果-m 不帶參數,如果我寫了參數,會怎么樣呢?下面看測試
在調用 getopt_long 以后, optind 的值隨之變化 。在while循環后,我們再把開始的命令行參數打印出來,看一下有什么不同。
把上面的代碼命名為: getopt_long.c
編譯,可執行文件為 a.out
$ gcc ?getopt_long.c ??
$ ./a.out -m -y
before:
arg:1 : -m
arg:2 : -y
My name is A.
His name is B.
optind:3
after:
arg:1 : -m
arg:2 : -y
$ ./a.out -m -y -l banana
before:
arg:1 : -m
arg:2 : -y
arg:3 : -l
arg:4 : banana
My name is A.
His name is B.
Our love is banana!
optind:5
after:
arg:1 : -m
arg:2 : -y
arg:3 : -l
arg:4 : banana
$./a.out -m lisi -y zhangsan ?-l banana ?aaa
before:
arg:1 : -m
arg:2 : lisi
arg:3 : -y
arg:4 : zhangsan
arg:5 : -l
arg:6 : banana
arg:7 : aaa
My name is A.
His name is B.
Our love is banana!
optind:5
after:
arg:1 : -m
arg:2 : -y
arg:3 : -l
arg:4 : banana
arg:5 : lisi?arg:6 : zhangsan?arg:7 : aaa
注意 argv 里面值的順序已經和原來不一樣了,對命令行的參數重新組織了一下順序,也就是不認識的命令行參數,都放在了argv的最后,其中 optind 指向了這些沒有被解釋的參數的第一個。
optind有作用吧!如果你想輸出哪些命令行參數沒有被識別,可以打印出來
for (i=optind; i<argc; i++)
printf("%s\n", argv[i]); ?即可
附:如果是長參數,則使用 --, 如 --help, 因為 -help時,(選項不需要參數的情況) 會把它當成 四個選項, -h -e -l -p. 所以使用長參數時,要用兩個 橫線 --




#include <getopt.h>
#include <stdio.h>
#include <stdlib.h>
const char* program_name;
void print_usage (FILE* stream, int exit_code)
{
? ? ? ? fprintf (stream, "Usage: %s options [ inputfile ... ]\n", program_name);
? ? ? ? fprintf (stream, " -h --help ? ? ? ? ? ? ? ? ? ? ? 顯示這個幫助信息.\n"
? ? ? ? ? ? ? ? ? ? ? ? ?" -o --output filename 將輸出定位到文件.\n"
? ? ? ? ? ? ? ? ? ? ? ? ?" -v --version ? ? ? ? ? ? ? ? ?打印版本信息.\n");
? ? ? ? exit (exit_code);
}


int main (int argc, char* argv[])
{
? ? ? ? int next_option;//下一個要處理的參數符號
? ? ? ? int haveargv = 0;//是否有我們要的正確參數,一個標識


? ? ? ?
? ? ? ? const char* const short_options = "ho:v";


? ? ? ?
? ? ? ? const struct option long_options[] = {
? ? ? ? ? ? ? ? { "help", ? ? ? ?0, ? ? NULL, ? ?'h' },
? ? ? ? ? ? ? ? { "output", ? ? ?1, ? ? NULL, ? ?'o' },
? ? ? ? ? ? ? ? { "version", ? ? 0, ? ? NULL, ? ?'v' },
? ? ? ? ? ? ? ? { NULL, ? ? ? ? ?0, ? ? NULL, ? ? 0 ?}};//最后一個元素標識為NULL


? ? ? ?
? ? ? ? const char *output_filename = NULL;
? ? ? ?
? ? ? ? int verbose = 0;
? ? ? ?
? ? ? ? program_name = argv[0];


? ? ? ? do
? ? ? ? {
? ? ? ? ? ? ? ? next_option = getopt_long (argc, argv, short_options, long_options, NULL);
? ? ? ? ? ? ? ? switch (next_option)
? ? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? ? ? ? case 'h': ? ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? haveargv = 1;
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? print_usage (stdout, 0);
? ? ? ? ? ? ? ? ? ? ? ? case 'o': ? ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? output_filename = optarg;
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? haveargv = 1;
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? break;
? ? ? ? ? ? ? ? ? ? ? ? case 'v': ? ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? verbose = 1;
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? haveargv = 1;
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? break;
? ? ? ? ? ? ? ? ? ? ? ? case ':': ? ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? break;
? ? ? ? ? ? ? ? ? ? ? ? case '?': ? ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? print_usage (stderr, 1);
? ? ? ? ? ? ? ? ? ? ? ? case -1: ? ? ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? if (!haveargv)
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? print_usage (stderr, 1);
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?}
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? break;
? ? ? ? ? ? ? ? ? ? ? ? default: ? ? ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? print_usage (stderr, 1);
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? break;
? ? ? ? ? ? ? ? }
? ? ? ? }while (next_option != -1);


? ? ? ? printf("optind.................%d\n",optind);


? ? ? ? if (haveargv)
? ? ? ? {
? ? ? ? ? ? ? ? int i;
? ? ? ? ? ? ? ? for (i = optind; i < argc; ++i)
? ? ? ? ? ? ? ? printf ("Argument: %s\n", argv[i]);
? ? ? ? }


? ? ? ? return 0;
}






getopt的用法與optarg


getopt被用來解析命令行選項參數。就不用自己寫東東處理argv了。
#include <unistd.h>
extern char *optarg; ?//選項的參數指針
extern int optind, ? //下一次調用getopt的時,從optind存儲的位置處重新開始檢查選項。?
extern int opterr, ?//當opterr=0時,getopt不向stderr輸出錯誤信息。
extern int optopt; ?//當命令行選項字符不包括在optstring中或者選項缺少必要的參數時,該選項存儲在optopt中,getopt返回'?’、
int getopt(int argc, char * const argv[], const char *optstring);
調用一次,返回一個選項。 在命令行選項參數再也檢查不到optstring中包含的選項時,返回-1,同時optind儲存第一個不包含選項的命令行參數。
首先說一下什么是選項,什么是參數。
字符串optstring可以下列元素,
1.單個字符,表示選項,
2.單個字符后接一個冒號:表示該選項后必須跟一個參數。參數緊跟在選項后或者以空格隔開。該參數的指針賦給optarg。
3 單個字符后跟兩個冒號,表示該選項后必須跟一個參數。參數必須緊跟在選項后不能以空格隔開。該參數的指針賦給optarg。(這個特性是GNU的擴張)。
getopt處理以'-’開頭的命令行參數,如optstring="ab:c::d::",命令行為getopt.exe -a -b host -ckeke -d haha?
在這個命令行參數中,-a和-h就是選項元素,去掉'-',a,b,c就是選項。host是b的參數,keke是c的參數。但haha并不是d的參數,因為它們中間有空格隔開。
還要注意的是默認情況下getopt會重新排列命令行參數的順序,所以到最后所有不包含選項的命令行參數都排到最后。
如getopt.exe -a ima -b host -ckeke -d haha, 都最后命令行參數的順序是: -a -b host -ckeke -d ima haha
如果optstring中的字符串以'+'加號開頭或者環境變量POSIXLY_CORRE被設置。那么一遇到不包含選項的命令行參數,getopt就會停止,返回-1。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc, char **argv)
{
int result;
? ? opterr = 0; ?//使getopt不行stderr輸出錯誤信息
? ? while( (result = getopt(argc, argv, "ab:c::")) != -1 )
{
switch(result)
{
case 'a':
printf("option=a, optopt=%c, optarg=%s\n", optopt, optarg);
break;
case 'b':
printf("option=b, optopt=%c, optarg=%s\n", optopt, optarg);
break;
case 'c':
printf("option=c, optopt=%c, optarg=%s\n", optopt, optarg);
break;
case '?':
printf("result=?, optopt=%c, optarg=%s\n", optopt, optarg);
break;
default:
printf("default, result=%c\n",result);
break;
}
printf("argv[%d]=%s\n", optind, argv[optind]);
}
printf("result=-1, optind=%d\n", optind); ? //看看最后optind的位置
? ? for(result = optind; result < argc; result++)
printf("-----argv[%d]=%s\n", result, argv[result]);
?//看看最后的命令行參數,看順序是否改變了哈。
for(result = 1; result < argc; result++)
printf("\nat the end-----argv[%d]=%s\n", result, argv[result]);
return 0;
}


unistd里有個 optind 變量,每次getopt后,這個索引指向argv里當前分析的字符串的下一個索引,因此
argv[optind]就能得到下個字符串,通過判斷是否以 '-'開頭就可。下面是個測試程序
#include <stdio.h>
#include <unistd.h>
int main(int argc, char* argv[])
{
int tmp = 4;


while( (tmp = getopt(argc, argv, "abck")) != -1 ?)
{


printf("-%c\t", tmp);
int opt = optind ;
while( opt < argc )
{
if ( argv[opt][0] != '-' )
{
printf("%s\t", argv[opt]);
opt ++;
}
else
break;
}
printf("\n");
}
getchar();
}














函數說明 ?getopt()用來分析命令行參數。參數argc和argv是由main()傳遞的參數個數和內容。參數optstring 則代表欲處理的選項字符串。此函數會返回在argv 中下一個的選項字母,此字母會對應參數optstring 中的字母。如果選項字符串里的字母后接著冒號“:”,則表示還有相關的參數,全域變量optarg 即會指向此額外參數。如果getopt()找不到符合的參數則會印出錯信息,并將全域變量optopt設為“?”字符,如果不希望getopt()印出錯 信息,則只要將全域變量opterr設為0即可。


返回值 ?如果找到符合的參數則返回此參數字母,如果參數不包含在參數optstring 的選項字母則返回“?”字符,分析結束則返回-1。


范例 ?#include<stdio.h>
#include<unistd.h>
int main(int argc,char **argv)
{
int ch;
opterr = 0;
while((ch = getopt(argc,argv,”a:bcde”))!= -1)
switch(ch)
{
case ‘a’:
printf(“option a:’%s’\n”,optarg);
break;
case ‘b’:
printf(“option b :b\n”);
break;
default:
printf(“other option :%c\n”,ch);
}
printf(“optopt +%c\n”,optopt);
}


執行 ?$./getopt –b
option b:b
$./getopt –c
other option:c
$./getopt –a
other option :?
$./getopt –a12345
option a:’12345’

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/383361.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/383361.shtml
英文地址,請注明出處:http://en.pswp.cn/news/383361.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

GitHub相關

git是一個版本控制工具. 主要解決三個問題 代碼被喵星人吃掉了.產品經理反復修改需求, 需要同時維護多個版本代碼.多人協同開發. 安裝 git for windows 這個是一個git的windows系統的命令行版本 https://git-scm.com/downloads 下載會很慢很慢 使用 Github 創建項目 注冊…

linux中bin與sbin目錄的作用及區別介紹

在linux系統中&#xff0c;有兩個重要的目錄&#xff1a;bin與sbin&#xff0c;分別包括/bin、/usr/bin/與/sbin、/usr/sbin/。 bin: bin為binary的簡寫&#xff0c;主要放置系統的必備執行文件&#xff0c;例如: cat、cp、chmod df、dmesg、gzip、kill、ls、mkdir、more、m…

c++起始(名詞修飾,extern “C” ,引用)

名字修飾(name Mangling) 在C/C中&#xff0c;一個程序要運行起來&#xff0c;需要經歷以下幾個階段&#xff1a;預處理、編譯、匯編、鏈接。 Name Mangling是一種在編譯過程中&#xff0c;將函數、變量的名稱重新改編的機制&#xff0c;簡單來說就是編譯器為了區分各 個函數…

Linux進程間通信方式--本地socket

先上一個代碼 服務端&#xff1a; [cpp] view plaincopy //s_unix.c #include <stdio.h> #include <sys/types.h> #include <sys/socket.h> #include <sys/un.h> #define UNIX_DOMAIN "/tmp/UNIX.domain" int main(void) { so…

extern和static的區別

c語言中的 static&#xff1a; 修飾局部變量&#xff1a;存放在靜態數據區&#xff0c;生命周期位整個程序結束&#xff0c;但作用于仍為函數局部。 修飾全局變量&#xff1a;無法被同一工程其他源文件訪問。 修飾函數&#xff1a;與全局變量類似。 extern&#xff1a; 可被…

RT5350原廠SDK及AP移植步驟詳解

最近想搞一下rt5350&#xff0c;所以找了個原廠的SDK包進行了編譯&#xff0c;很快路由器就可以用了&#xff0c;把我的編譯操作步驟寫了下分享給更多的愛好者&#xff0c;供大家參靠&#xff0c;下一步準備移植攝像頭玩玩。有興趣的可以一起交流。 RT5350移植Toolchain工具的安…

linux系統編程之進程概念(操作系統---管理,進程創建,進程狀態,進程優先級, 環境變量,程序地址空間,進程O(1)調度方法)

系統編程&#xff1a; 進程概念->進程控制->基礎IO->進程間通信->進程信號->多線程進程概念 馮諾依曼體系結構----現代計算機硬件體系結構 馮諾依曼體系結構----現代計算機硬件體系結構 計算機五大硬件單元&#xff1a;輸入設備&#xff1a;鍵盤輸出設備&#…

Make Menuconfig詳解 (配置內核選擇)

Make Menuconfig簡介 make menuconfig 圖形化的內核配置make mrproper -----刪除不必要的文件和目錄. #make config&#xff08;基于文本的最為傳統的配置界面&#xff0c;不推薦使用&#xff09; #make menuconfig&#xff08;基于文本選單的配置界面&#xff0c;字符終端下…

Linux系統編程之進程控制(進程創建,fork函數,進程中止,進程等待,程序替換)

進程創建 fork()------復制&#xff0c;返回值&#xff0c;寫時復制 vfork()創建子進程—子進程與父進程共用同一塊虛擬地址空間&#xff0c; 為了防止調用棧混亂&#xff0c;因此阻塞父進程直到子進程調用exit&#xff08;&#xff09;退出或者進行程序替換 vfork創建的子…

Linux內核配置系統淺析

隨著 Linux 操作系統的廣泛應用&#xff0c;特別是 Linux 在嵌入式領域的發展&#xff0c;越來越多的人開始投身到 Linux 內核級的開發中。面對日益龐大的 Linux 內核源代碼&#xff0c;開發者在完成自己的內核代碼后&#xff0c;都將面臨著同樣的問題&#xff0c;即如何將源代…

Linux系統編程下做一個簡易的shell

自主實現一個shell--------minshell shell&#xff1a;命令行解釋器-------解釋執行用戶的輸入&#xff08;完成相對應的功能&#xff09; 步驟 1. 獲取標準輸入中的字符串 2. 對字符串進行解析[ls -l -a][ls ] [-l ] [-a] 3. 創建子進程 4. 子進程中進行程序替換 5. 父進程…

C++起始(內聯函數,宏的優缺點,const關鍵字,auto關鍵字(C++11)基于范圍的for循環(C++11). 指針空值nullptr(C++11))

內聯函數 概念 以inline修飾的函數叫做內聯函數&#xff0c;編譯時C編譯器會在調用內聯函數的地方展開&#xff0c;沒有函數壓棧的開銷&#xff0c; 內聯函數提升程序運行的效率 函數前增加inline關鍵字將其改成內聯函數&#xff0c;在編譯期間編譯器會用函數體替換函數的調用…

linux內核中的匯編語言

在Linux內核代碼中&#xff0c;有一部分是用匯編語言編寫的。其大部分是關于中斷與異常處理的底層程序&#xff0c;還有就是與初始化有關的程序&#xff0c;以及一些核心代碼中調用的公用子程序。 用匯編語言編寫內核代碼中的部分代碼&#xff0c;大體上是出于如下幾個方面考慮…

數據結構課程設計---c語言實現通訊錄(動態擴容+文件存儲)

1 題目一 &#xff1a; 通訊錄 1.1問題描述 編寫一個通訊錄管理系統&#xff0c;以把所學數據結構知識應用到實際軟件開發中去。每條信息至包含 &#xff1a;姓名&#xff08;NAME &#xff09;街道&#xff08;STREET&#xff09;城市&#xff08;CITY&#xff09;郵編&#…

linux內核panic

1. Linux Kernel Panic的產生的原因 panic是英文中是驚慌的意思&#xff0c;Linux Kernel panic正如其名&#xff0c;linux kernel不知道如何走了&#xff0c;它會盡可能把它此時能獲取的全部信息都打印出來。 有兩種主要類型kernel panic&#xff0c;后面會對這兩類panic做詳細…

數據結構課程設計------c實現散列表(二次探測再哈希)電話簿(文件存儲)

題目二 &#xff1a;散列表的設計與實現 2.1問題描述 設計散列表實現電話號碼查找系統&#xff0c;使得平均查找長度不超過2基本要求 &#xff08;1&#xff09;設每個記錄有下列數據項&#xff1a;電話號碼、用戶名、地址&#xff1b; &#xff08;2&#xff09;從鍵盤輸入各…

科技論文----論搜索引擎現狀及發展趨勢

搜索引擎現狀及發展趨勢 【摘要】 隨著最近10年中國互聯網的快速發展菜互聯網已經徹底改變了人們的生活方式&#xff0c;而在互聯網的發展過程中。搜索引擎發揮了巨大的推動作用。本文對搜索引擎的發展歷史采用的技術&#xff0c;發展現狀出現的問題以及未來發展方向進行了綜述…

inittab文件格式

/etc/inittab文件是Linux系統第一個進程init的配置文件。其每個記錄占一行&#xff0c;每行最多512個字符。該文件的每個記錄的格式為&#xff1a; id:runlevel:action:process 其中&#xff0c;id是一個不超過4個字符的標識&#xff0c;用來唯一標識一條記錄。runlevel表明該條…

數據結構課程設計------掃雷游戲(升級版,可展開)

本程序由團隊中的一個人所寫&#xff0c;本人看懂并寫下此文章 題目&#xff1a;掃雷 3.1問題描述 掃雷游戲 [基本要求] &#xff08;1&#xff09;完成棋盤的初始化并在標準顯示器中顯示 &#xff08;2&#xff09;通過輸入行列值確定用戶輸入 &#xff08;3&#xff09;游…

C語言的編譯鏈接過程的介紹

發布時間: 2012-11-08 10:17 作者: 未知 來源: 51Testing軟件測試網采編 字體: 小 中 大 | 上一篇 下一篇 | 打印 | 我要投稿 | 推薦標簽&#xff1a; DotNet 軟件開發 | 感言十年 C語言的編譯鏈接過程要把我們編寫的一個c程序&#xff08;源代碼&#x…