0Pricing
C Academy · レッスン

オプションの解析

フラグを処理します。

「オプションの解析」はCoddyKit上の無料C Academyレッスンです。 これはレッスン2/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはC Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 C Academyコースには全4レッスンが含まれています。

オプションと位置引数

コマンドライン引数には 2 種類あります。位置引数はファイル名のような値です。オプション(フラグとも呼ばれます)は、-v や --help のようにダッシュで始まります。

このレッスンでは、フラグを手動で検出して処理する方法を説明します。

#include <stdio.h>

int main(int argc, char *argv[]) {
    for (int i = 1; i < argc; i++) {
        if (argv[i][0] == '-')
            printf("option: %s\n", argv[i]);
        else
            printf("value:  %s\n", argv[i]);
    }
    return 0;
}

フラグを検出する

特定のフラグを確認するには、各引数を strcmp で比較します。

ここでは、-v が見つかったときに詳細モード用の真偽値を設定します。

#include <stdio.h>
#include <string.h>

int main(int argc, char *argv[]) {
    int verbose = 0;
    for (int i = 1; i < argc; i++) {
        if (strcmp(argv[i], "-v") == 0)
            verbose = 1;
    }
    printf("verbose = %d\n", verbose);
    return 0;
}

長いオプションに対応する

多くのツールでは、短い形式(-h)と長い形式(--help)の両方を使用できます。

2 つの比較を || でつないで、どちらの表記にも対応します。

#include <stdio.h>
#include <string.h>

int main(int argc, char *argv[]) {
    for (int i = 1; i < argc; i++) {
        if (strcmp(argv[i], "-h") == 0 ||
            strcmp(argv[i], "--help") == 0) {
            printf("Usage: prog [options]\n");
            return 0;
        }
    }
    printf("No help requested\n");
    return 0;
}

値を取るオプション

-o output.txt のように、引数を必要とするフラグもあります。このようなフラグが見つかった場合、argv の次の要素がその値です。

ループのインデックスを進め、末尾を超えていないことを確認してください。

#include <stdio.h>
#include <string.h>

int main(int argc, char *argv[]) {
    const char *output = "default.txt";
    for (int i = 1; i < argc; i++) {
        if (strcmp(argv[i], "-o") == 0 && i + 1 < argc) {
            output = argv[++i];
        }
    }
    printf("Output file: %s\n", output);
    return 0;
}

値がない場合を処理する

-o が最後の引数の場合、その後に値はありません。argv[i+1] を読み取ると範囲外アクセスになります。

次のトークンを使用する前に、必ず i + 1 < argc を確認し、そうでなければエラーを報告してください。

#include <stdio.h>
#include <string.h>

int main(int argc, char *argv[]) {
    for (int i = 1; i < argc; i++) {
        if (strcmp(argv[i], "-n") == 0) {
            if (i + 1 >= argc) {
                printf("Error: -n needs a value\n");
                return 1;
            }
            printf("n = %s\n", argv[++i]);
        }
    }
    return 0;
}

真偽値フラグと値を組み合わせる

実用的なパーサーでは、複数のフラグを同時に管理します。真偽値だけのものもあれば、値を持つものもあります。設定ごとに別の変数を使用してください。

#include <stdio.h>
#include <string.h>

int main(int argc, char *argv[]) {
    int verbose = 0;
    const char *name = "world";
    for (int i = 1; i < argc; i++) {
        if (strcmp(argv[i], "-v") == 0) verbose = 1;
        else if (strcmp(argv[i], "-name") == 0 && i+1 < argc) name = argv[++i];
    }
    if (verbose) printf("verbose mode\n");
    printf("Hello, %s\n", name);
    return 0;
}

オプションの終わりを認識する

慣例では、単独の -- がオプションの終わりを示します。それ以降は、ダッシュで始まっていてもすべて位置引数として扱われます。

これにより、- で始まるファイル名も渡せます。

#include <stdio.h>
#include <string.h>

int main(int argc, char *argv[]) {
    int opts_done = 0;
    for (int i = 1; i < argc; i++) {
        if (!opts_done && strcmp(argv[i], "--") == 0) {
            opts_done = 1;
            continue;
        }
        printf("%s: %s\n", opts_done ? "value" : "token", argv[i]);
    }
    return 0;
}

位置引数を収集する

フラグとファイルのリストを受け取りたい場合がよくあります。認識したオプションをスキップし、残りを位置引数として保存します。

#include <stdio.h>
#include <string.h>

int main(int argc, char *argv[]) {
    for (int i = 1; i < argc; i++) {
        if (argv[i][0] == '-') continue;
        printf("file: %s\n", argv[i]);
    }
    return 0;
}

未知のオプションを処理する

使いやすいツールは、未知のフラグを黙って無視するのではなく報告します。既知のオプションと照合し、それ以外の場合は警告してください。

#include <stdio.h>
#include <string.h>

int main(int argc, char *argv[]) {
    for (int i = 1; i < argc; i++) {
        if (argv[i][0] != '-') continue;
        if (strcmp(argv[i], "-v") != 0)
            printf("Unknown option: %s\n", argv[i]);
    }
    return 0;
}

オプションの値を変換する

オプションの値は文字列として渡されます。数値の場合は strtol で変換します。この関数は、終端ポインターを使って解析エラーも報告できます。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(int argc, char *argv[]) {
    int count = 1;
    for (int i = 1; i < argc; i++) {
        if (strcmp(argv[i], "-c") == 0 && i+1 < argc)
            count = (int) strtol(argv[++i], NULL, 10);
    }
    printf("count = %d\n", count);
    return 0;
}

本格的なパーサーが役立つ理由

手動解析でも動作しますが、短いフラグの結合(-vf)、= 構文(--name=foo)、順序に関する規則などが加わると複雑になります。

次に説明する標準の getopt 関数を使えば、こうした規則を自分で処理する必要がありません。

#include <stdio.h>

int main(int argc, char *argv[]) {
    printf("Parsed %d tokens manually\n", argc - 1);
    return 0;
}

理解度チェック

オプション解析で起こりやすい問題についての理解度を確認しましょう。

まとめ

オプションを手動で解析する方法を学びました。

  • フラグは - で始まり、strcmp で比較します。
  • || を使って短い形式と長い形式に対応します。
  • 値を取るオプションは次のトークンを消費するため、i + 1 < argc で確認します。
  • -- でオプション解析を終了し、未知のフラグを報告します。数値は strtol で変換します。

よくある質問

「オプションの解析」レッスンは無料ですか?

はい。「オプションの解析」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、C Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 C Academyコースには全4レッスンが含まれています。

「オプションの解析」で何を学びますか?

フラグを処理します。 ブラウザで直接実行するハンズオンコードでC Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。

C Academyを始めるのに経験は必要ですか?

事前経験は必要ありません。CoddyKitのC Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン2/4です。

「オプションの解析」レッスンにはどのくらい時間がかかりますか?

ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。

このC Academyレッスンでコードを書いて実行できますか?

はい。すべてのC Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。

このコースのすべてのレッスン

  1. argc と argv
  2. オプションの解析
  3. getopt
  4. CLI ツールの作成
← C Academyに戻る