설명
프로그램을 실행할 때, 옵션을 지정할 수 있습니다. 예를 들어 아래와 같이 프로그램을 실행할 수 있습니다.
]$ ./sample-app -r -c -f test.txt
실행 시 입력한 옵션을 프로그램에서 처리하기 위해서 main()함수의 argc 나 argv를 직접 사용하기에는 여러 모로 불편합니다. 대신에 getopt() 함수를 이용하는 것이 편합니다.
그러나 getopt() 함수로 처리하는 옵션은 -r -c 와 같이 문자 하나만 사용하는 옵션에만 사용할 수 있습니다. 즉, 아래와 같이 긴 이름의 옵션을 사용하지 못합니다.
]$ ./sample-app --repeat --filename=test.txt
옵션이라도 문자 하나 보다는 긴 이름의 옵션을 사용하는 것이 편할 것입니다. 이런 긴 이름의 옵션을 쉽게 사용할 수 있도록 해주는 함수가 getopt_long() 함수가 되겠습니다.
getopt()와 다른 점, struct option
getopt()를 사용하는 옵션은 - 문자 하나만 사용합니다. 그러나 getopt_long()를 사용하는 긴 옵션은 -- 처럼 문자 두개로 입력해야 합니다.
getopt_long() 함수를 사용하기 위해서는 getopt() 함수와 달리 긴 이름의 옵션 정보를 미디 준비해야 합니다. 예를 들어,
- 옵션에 --opt55를 입력했다면 var55 변수에 55라는 값을 구하고, 옵션에 없다면 0의 값을 가지게 하겠습니다.
- 옵션에 --opt99를 입력했다면 var99 변수에 99라는 값을 구하고, 옵션에 없다면 0의 값을 가지게 하겠습니다.
- --repeat 옵션이 있는지 여부를 확인 하겠습니다.
- --name= 옵션을 사용했다면 옵션에 지정한 문자열을 구하겠습니다.
이와 같이 처리해야할 옵션이 결정되었다면 아래와 같이 struct option을 작성합니다.
struct option options[] = { {"opt55" , 0, &var55, 55}, {"opt99" , 0, &var99, 99}, {"repeat", 0, 0, 0}, {"name" , 1, 0, 0}, {0, 0, 0, 0} };
struct option은 아래와 같이 구성되어 있습니다.
struct option { const char *name; // 옵션의 긴 이름입니다. int has_arg; // 옵션에 해당하는 자료, 즉 --name=test.c 처럼 인수가 필요한지
// 여부를 지정합니다. // 0 : 필요 없음 // 1 : 필요 함 int *flag; // 옵션이 입력되었다면 지정한 값을 받을 수 있는 변수 주소입니다. int val; // 옵션이 입력되었다면 여기에 지정한 값을 flag 변수에 대입합니다. };
struct opton 구조에 따라 각 행의 뜻하는 바를 보겠습니다.
- {"opt55" , 0, &var55, 55}
옵션의 긴 이름은 opt55 이며,
옵션에 필요한 인자는 없습니다. 즉, --opt55=어쩌구저쩌구 라고 "=어쩌구저쩌구"를 넣을 수 없습니다.
옵션이 지정되었다면 var55 변수에 55값을 넣어라가 되겠습니다. - {"opt99" , 0, &var9955, 995}
옵션의 긴 이름은 opt99 이며,
옵션에 필요한 인자는 없습니다.
옵션이 지정되었다면 var99 변수에 99값을 대입하게 됩니다. - {"repeat", 0, 0, 0}
옵션의 긴 이름은 repeat 이며,
필요한 추가 자료는 없습니다.
옵션이 있는지의 여부를 받는 포인터 변수도 없습니다. - {"name" , 1, 0, 0}
옵션의 긴 이름은 name이며,
=로 지정하는 자료가 필요합니다. 없으면 에러 메시지가 출력됩니다.
옵션이 있는지의 여부를 받는 포인터 변수가 없습니다.
실행 여부에 따라 아래와 같은 결과를 얻을 수 있습니다.
]$ ./sample --opt55 --repeat -name=test.txt
- var99 변수 값에는 변동 없음
- var55 변수에 55를 대입
- repeat 옵션이 지정되었음을 알게됨
- name의 문자열 데이터는 "test.txt"
함수 사용 예
프로그램 작성 예입니다.
#include <stdio.h> #include <getopt.h> static int var55; static int var99; int main( int argc, char **argv) { struct option options[] = { {"opt55" , 0, &var55, 55}, {"opt99" , 0, &var99, 99}, {"repeat", 0, 0, 0}, {"name" , 1, 0, 0}, {0, 0, 0, 0} }; char *name; int index = 0; while( 1) { opt = getopt_long( argc, argv, "", options, &index); if ( -1 == opt) break; // 모든 옵션을 확인했으면 루프 종료 switch( opt) { case 0: if ( options[index].flag != 0) break; // 변수 주소 지정이 없다면 // 다음 옵션을 확인합니다. // 즉, --repeat와 --name이 아니면 // 스킵합니다. printf("옵션 %s", options[index].name); if ( NULL != optarg) printf("=%s", optarg); printf("\n"); break; } /* switch 의 끝*/ } /* while 의 끝 */ printf( "var55= %d\n", var55); printf( "var99= %d\n", var99); /* 남아있는 코맨드 라인 인수들을( 옵션이 없는) 출력하라. */ if (optind < argc) { printf ("non-option ARGV-elements: "); while (optind < argc) printf ("%s ", argv[optind++]); putchar ('\n'); } }
실행하면 아래와 같습니다.
]$ ./a.out --opt55 --name=test.c --repeat
옵션 name=test.c
옵션 repeat
var55= 55
var99= 0
getopt()와 같은 사용법
또한 getopt() 와 같이 문자 하나 옵션도 사용할 수 있습니다. 이 옵션 사용은 getopt()와 같습니다. 즉, 아래와 같이 getopt_long() 함수를 호출하면 -r, -f 옵션을 사용할 수 있습니다.
opt = getopt_long( argc, argv, "rf:", options, &index);
아래의 함수 설명 예에서는 getopt() 함수처럼 문자 하나 옵션까지 처리하는 예를 올렸습니다.
헤더 | getopt.h | |||||||
형태 | int getopt(int argc, char * const argv[], const char *optstring); | |||||||
인수 | 위의 설명을 참고 | |||||||
반환 |
|
예제
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <getopt.h> #define TRUE 1 #define FALSE 0 static int var55; static int var99; int main( int argc, char **argv) { struct option options[] = { {"opt55" , 0, &var55, 55}, {"opt99" , 0, &var99, 99}, {"repeat", 0, 0, 0}, {"name" , 1, 0, 0}, {0, 0, 0, 0} }; char *name = NULL; int is_repeat = FALSE; int index = 0; int opt; while( 1) { opt = getopt_long( argc, argv, "rf:", options, &index); if ( -1 == opt) break; // 모든 옵션을 확인했으면 루프 종료 switch( opt) { case 0: switch( index) { case 2 : // options[2]에 해당하는 repeat 라면 is_repeat = TRUE; break; case 3 : // options[3]에 해당하는 name 이라면 if ( NULL != optarg) // 인수가 있다면 { name = malloc( strlen( optarg)+1); memcpy( name, optarg, strlen(optarg)+1); } break; } // switch index break; case 'r': printf("-r 옵션을 사용\n", optarg); break; case 'f': printf("-f 옵션에 대한 값 지정은 %s 입니다.\n", optarg); break; case '?': // 이 처리는 하지 않아도 getopt_long()에서 처리합니다. // 즉, 생략해도 됩니다. break; } // switch opt } // while printf( "var55= %d\n", var55); printf( "var99= %d\n", var99); if ( is_repeat) printf( "repeat 옵션이 있습니다.\n"); else printf( "repeat 옵션이 없습니다.\n"); if ( NULL != name) printf( "name은 %s 입니다.\n", name); }
]$ ./a.out --opt99 --repeat --name=test.c -f test3.c -x --xxx
-f 옵션에 대한 값 지정은 test3.c 입니다.
./a.out: invalid option -- x
./a.out: unrecognized option `--xxx'
var55= 0
var99= 99
repeat 옵션이 있습니다.
name은 test.c 입니다.
]$