どの C プログラムでも、コマンド ライン引数argv[0]
は、プログラムの呼び出しに使用される名前を指します。空の文字列を指す状況はあります""
か?
このような場合のコード スニペットの例が参考になります。
それは実装定義です。§5.1.2.2.1 の要約:
の値が
argc
0 より大きい場合、 inclusiveargv[0]
からargv[argc-1]
inclusive までの配列メンバーには、プログラムの起動前にホスト環境によって実装定義の値が与えられる文字列へのポインターが含まれます。その目的は、ホスト環境の他の場所からプログラムを開始する前に決定された情報をプログラムに提供することです。[...]の値が
argc
0 より大きい場合、 が指す文字列argv[0]
はプログラム名を表します。argv[0][0]
プログラム名がホスト環境から利用できない場合、ヌル文字になります。[...]
したがって、argc
がゼロより大きい場合は、空の文字列にならないという意図がありますが、そうなる可能性があります。argv[0]
( with argc
equal to n
、argv[0]
throughargv[n - 1]
は null になることはなく、常に文字列を指すことに注意してください。ただし、文字列自体は空である可能性があります。n
is がゼロの場合argv[0]
は null です。)
もちろん、実際には、ターゲットとするプラットフォームが必要に応じて動作することを確認するだけで済みます。
はい。
C 言語標準ではargv[0]
、 がヌル ポインターになる可能性、または空の文字列 ( ""
) を指す可能性が明示的に認められています。N1256 5.1.2.2.1p2:
argcの値は非負でなければなりません。
argv[argc]は null ポインターでなければなりません。
[...]
argcの値が0 より大きい場合、argv[0]が指す文字列はプログラム名を表します。プログラム名がホスト環境から利用できない場合、 argv[0][0]はヌル文字になります。argcの値が1 より大きい場合、argv[1]からargv[argc-1]が指す文字列はプログラム パラメータを表し ます。
Unix ライクなシステムでは、プログラムは一連exec()
の関数 ( execl()
、execlp()
など) の 1 つによって呼び出されます。これにより、呼び出し元は関数に渡される引数を正確に指定できますmain()
。(C 標準によって課せられた要件に違反する方法でプログラムを呼び出すことさえ可能です。)
標準では、argv[0]
(nullでも空でもないと仮定して)「プログラム名を表す」と述べていることに注意してください。標準は、プログラム名をどのように表すかについて意図的にあいまいです。特に、プログラムを呼び出すことができる名前を提供する必要はありません (標準では、プログラムを名前で呼び出すことさえ要求していないため)。
他の回答者は C 標準を引用しており、and または it が空の文字列 ( ) である可能性があることを示してargv[0]
いNULL
ます""
。これが発生する可能性があることを前提としてプログラムを作成する必要があります。そうしないと、(小さな) セキュリティ リスクが発生するからです。プログラムを呼び出してargv
、攻撃者が望むものを設定するのは簡単です。証明として、次の 2 つのプログラムを考えてみましょう。最初のものは、echoargv.c
の内容を出力しますargv
:
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char **argv) {
int i;
for (i = 0; i < argc; ++i)
printf("argv[%d] = \"%s\"\n", i, argv[i]);
exit(0);
}
2 番目のargv0
は、他のプログラムを呼び出し、ユーザーが他のプログラムの argv を指定できるようにします。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc, char **argv) {
(void) execv(argv[1], argv+2);
perror("execv");
exit(1);
}
(これは Posix 固有のバージョンです。非標準環境では変更が必要になる場合があります。)
それらの使用方法は次のとおりです。
$ gcc -o echoargv echoargv.c
$ gcc -o argv0 argv0.c
$ ./argv0 ./echoargv
$ ./argv0 ./echoargv ''
argv[0] = ""
$ ./argv0 ./echoargv 'this is fun' 'it is fun indeed'
argv[0] = "this is fun"
argv[1] = "it is fun indeed"
$
argv0
セットechoargv
の最初の実行はargv[0]
NULL になります。2 回目の実行では、空の文字列になります。argv[0]
3 回目の実行は、ただの楽しみです。プログラムの実際の名前とは何の関係もないことに注意してください。
これはどのようにあなたを噛むことができますか?たとえば、使用法メッセージにプログラムの名前をやみくもに出力すると、次のようになります。
printf("usage: %s [options] [FILE]...\n", argv[0]);
より良い:
const char *program_name = "some default name"; /* (global) variable */
if (argv[0] && argv[0][0])
program_name = argv[0];
printf("usage: %s [options] [FILE]...\n", program_name);
これを行わないと、攻撃者がプログラムに勝手にセグメンテーション違反を引き起こしたり、プログラムにまったく間違ったことをユーザーに報告させたりする可能性があります。
argv[0] は、たとえば main 関数を直接呼び出す場合など、C では null になる可能性があります (C でいくつかのトリックを実行できます)。C++ でメインの直接呼び出しが許可されているかどうかはわかりません。