HOWTO · C++

C++에서 getopt를 사용하여 인수 처리

이 기사에서는 C++에서 getopt() 함수를 사용하여 인수를 처리하는 방법을 보여줍니다.

이 페이지의 내용

C++에서 짧은 명령줄 옵션을 파싱하려면 argc, argv, 그리고 각 옵션과 값 필요 여부를 선언하는 optstring을 getopt POSIX 함수에 전달합니다. 옵션 값은 optarg로 읽고, 파싱 후 남은 위치 인수는 optind부터 확인합니다. --help 같은 긴 옵션도 필요하면 getopt_long을 사용합니다.

C++에서 getopt 이해하기

getopt는 POSIX에 명시된 인터페이스이며 Unix 계열 시스템에서 흔히 사용할 수 있지만, C++ 표준 라이브러리에는 포함되지 않습니다. 해당 헤더를 제공하는 시스템에서는 <unistd.h>를 포함합니다. 이 함수는 argc와 argv를 읽고 파싱된 옵션을 한 번에 하나씩 반환합니다. 짧은 옵션은 -v처럼 문자 하나로 이루어집니다. -o report.txt처럼 옵션 뒤에 값을 지정할 수도 있습니다. getopt는 짧은 옵션만 파싱하므로 --output 같은 토큰에는 별도의 인터페이스가 필요합니다. 인터페이스와 반환 값 규칙은 POSIX getopt 명세를 참고하세요.

옵션 순서 같은 세부 동작과 사용 가능 여부는 플랫폼마다 다릅니다. 이식성이 중요하다면 대상 시스템의 헤더와 문서를 확인하세요. 아래 예제는 POSIX 인터페이스와 g++ 같은 C++ 컴파일러를 사용합니다.

짧은 옵션을 정의하고 인수 파싱하기

optstring에는 허용할 한 글자 옵션을 나열합니다. 문자 뒤에 :를 붙이면 해당 옵션이 값을 받는다는 뜻이며, getopt는 그 값을 optarg로 제공합니다. 예제에서 v는 플래그이고 o:는 출력 경로를 받습니다. 파싱 후 남은 위치 인수도 출력합니다. 파일을 main.cpp로 저장한 뒤 POSIX 계열 시스템에서 g++ -std=c++17 -Wall -Wextra -pedantic main.cpp -o app 명령으로 컴파일하세요.

다음 예제를 실행합니다.

이 섹션의 코드와 표시되는 레이블 또는 출력은 영어로 유지됩니다.

#include <iostream>
#include <unistd.h>

int main() {
    char app[] = "app";
    char verbose_option[] = "-v";
    char output_option[] = "-o";
    char output_path[] = "report.txt";
    char input_path[] = "input.csv";
    char* arguments[] = {app, verbose_option, output_option, output_path, input_path, nullptr};
    int argument_count = 5;
    bool verbose = false;
    const char* output = "result.txt";
    int option = 0;

    opterr = 0;
    while ((option = getopt(argument_count, arguments, ":vo:")) != -1) {
        switch (option) {
            case 'v':
                verbose = true;
                break;
            case 'o':
                output = optarg;
                break;
            case ':':
                std::cerr << "Option -" << static_cast<char>(optopt) << " requires a value\n";
                return 2;
            case '?':
            default:
                std::cerr << "Unknown option: -" << static_cast<char>(optopt) << '\n';
                return 2;
        }
    }

    std::cout << "verbose=" << (verbose ? "on" : "off") << '\n';
    std::cout << "output=" << output << '\n';
    for (int i = optind; i < argument_count; ++i) {
        std::cout << "input=" << arguments[i] << '\n';
    }
}
verbose=on
output=report.txt
input=input.csv

고정된 인수 배열을 사용해 예제를 단독으로 실행할 수 있게 했습니다. 일반 프로그램에서는 main이 받은 argc와 argv를 전달하면 됩니다. 앞에 콜론이 있는 optstring :vo:는 필수 값 누락과 알 수 없는 옵션을 구분합니다. v는 값을 받지 않고 o:는 값을 요구합니다. -o report.txt와 -oreport.txt는 모두 흔히 허용되는 표기입니다. optarg는 현재 처리 중인 옵션에 연결된 값을 가리킵니다.

오류와 남은 인수 처리하기

일반적으로 옵션 파싱이 끝나면 getopt는 -1을 반환합니다. 알 수 없는 옵션에는 ?를 반환합니다. 필수 값이 누락된 경우에도 optstring이 :로 시작하지 않으면 ?를 반환합니다. 앞에 콜론을 두는 규칙을 사용하면 값 누락에는 :, 알 수 없는 옵션에는 ?가 반환됩니다. optopt로 문제가 된 옵션 문자를 확인할 수 있습니다. 짧은 옵션 예제는 이 규칙을 사용하고 opterr을 0으로 설정합니다. 따라서 switch에서 각 오류 메시지를 한 번 출력하고 두 오류 모두에 대해 0이 아닌 상태를 반환합니다. 앞의 콜론을 생략하면 두 오류 모두 ?를 사용하므로 반환 값만으로는 구분할 수 없습니다. 같은 opterr 설정은 라이브러리 자체의 오류 메시지도 억제합니다.

파싱이 끝난 뒤 optind는 첫 번째 남은 인수의 인덱스입니다. optind부터 argc까지 반복해 파일 이름이나 다른 위치 값을 처리하세요. 일부 구현은 파싱 중 옵션과 피연산자의 순서를 바꾸지만, 다른 구현은 첫 피연산자에서 멈추거나 별도의 순서 제어 방식을 제공합니다. 옵션과 위치 인수가 섞여 있을 때 모든 플랫폼이 똑같이 처리한다고 가정하지 마세요.

긴 옵션에 getopt_long 사용하기

GNU <getopt.h> 확장을 제공하는 시스템에서는 getopt_long으로 긴 이름과 짧은 옵션을 함께 인식할 수 있습니다. 이 함수는 POSIX나 C++ 표준 라이브러리에 명시되어 있지 않습니다. GNU C 라이브러리 설명서의 getopt_long 항목에서 이 확장과 struct option 테이블을 설명합니다. 각 항목에는 긴 옵션 이름, 값이 필요 없는지 또는 필수·선택 값이 필요한지, 그리고 switch에 반환할 값이 들어갑니다. 이름이 null인 마지막 항목이 테이블의 끝을 표시합니다. 다음 독립 실행 예제는 --help와 --output FILE, 그리고 이에 대응하는 짧은 옵션을 받습니다.

이 섹션의 코드와 표시되는 레이블 또는 출력은 영어로 유지됩니다.

#include <getopt.h>
#include <iostream>

int main() {
    char app[] = "app";
    char help_option[] = "--help";
    char* arguments[] = {app, help_option, nullptr};
    int argument_count = 2;
    const option long_options[] = {
        {"help", no_argument, nullptr, 'h'},
        {"output", required_argument, nullptr, 'o'},
        {nullptr, 0, nullptr, 0}
    };
    const char* output = "result.txt";
    int option = 0;

    opterr = 0;
    while ((option = getopt_long(argument_count, arguments, ":ho:", long_options, nullptr)) != -1) {
        switch (option) {
            case 'h':
                std::cout << "Usage: app [-h] [-o FILE] [FILE...]\n";
                break;
            case 'o':
                output = optarg;
                break;
            case ':':
                std::cerr << "Option requires a value\n";
                return 2;
            case '?':
            default:
                std::cerr << "Unknown option\n";
                return 2;
        }
    }

    std::cout << "output=" << output << '\n';
    for (int i = optind; i < argument_count; ++i) {
        std::cout << "input=" << arguments[i] << '\n';
    }
}
Usage: app [-h] [-o FILE] [FILE...]
output=result.txt

실제 명령줄 프로그램에서는 main이 받은 argc와 argv를 사용하세요. getopt_long을 제공하는 시스템에서 g++ -std=c++17 -Wall -Wextra -pedantic main.cpp -o app 명령으로 컴파일할 수 있습니다. 예제의 고정 입력은 도움말 경로를 선택합니다. 입력을 --output report.txt input.csv로 바꾸면 출력 경로를 지정하고 input.csv는 optind를 통해 처리할 수 있도록 남습니다. 이 확장을 사용하기 전에 대상 플랫폼을 확인하세요.