web-dev-qa-db-ja.com

「argv [0] = name-of-executable」は受け入れられている標準ですか、それとも単なる一般的な規則ですか?

CまたはC++アプリケーションでmain()に引数を渡すと、argv[0]は常に実行可能ファイルの名前ですか?または、これは単なる一般的な慣習であり、常に100%真実であるとは限りませんか?

90
Mike Willekes

推測作業(教育を受けた推測作業でも)は楽しいものですが、確かに標準文書にアクセスする必要があります。たとえば、ISO C11の状態(私の強調):

argcの値がゼロより大きい場合、argv[0]が指す文字列represents =プログラム名;プログラム名がホスト環境から利用できない場合、argv[0][0]はヌル文字でなければなりません。

そのため、その名前がが使用可能な場合はプログラム名のみです。そして、それは "represents"プログラム名、必ずしもisプログラム名ではありません。その前のセクションでは次のように述べています。

argcの値がゼロより大きい場合、配列メンバーargv[0]argv[argc-1]には、プログラムの前にホスト環境によって実装定義の値が与えられる文字列へのポインターが含まれます。起動。

これは、以前の標準であるC99から変更されておらず、valuesでさえ標準によって規定されていないことを意味します-それは完全に実装次第です。

これは、ホスト環境が提供しない場合にプログラム名が空であり、ホスト環境doesは、「その他」が何らかの形でプログラム名を表す場合に提供します。もっとサディスティックな瞬間に、スワヒリ語に翻訳し、置換暗号を実行してから、逆バイト順で保存することを検討します:-)。

ただし、実装定義のdoesはISO標準で特定の意味を持ちます-実装は、その動作を文書化する必要があります。したがって、execファミリの呼び出しで好きなものをargv[0]に入れることができるUNIXでさえ、それを文書化する必要があります。

105
paxdiablo

exec*()呼び出しを持つ*nix型システムでは、argv[0]は、呼び出し元がexec*()呼び出しのargv0スポットに置くものになります。

シェルは、これがプログラム名であるという規則を使用しており、他のほとんどのプログラムは同じ規則に従っているため、argv[0]は通常プログラム名です。

しかし、不正なUnixプログラムはexec()を呼び出してargv[0]を好きなように作成できるため、C標準が何を言おうとも、この100%の時間を当てにすることはできません。

45

C++標準のセクション3.6.1によると:

argv [0]は、プログラムまたは「」を呼び出すために使用される名前を表すNTMBSの最初の文字へのポインタです。

いいえ、少なくとも標準では保証されていません。

8
anon

このページ 状態:

通常、要素argv [0]にはプログラムの名前が含まれていますが、これに依存するべきではありません-とにかくプログラムが自分の名前を知らないことは珍しいことです!

ただし、他のページは、常に実行可能ファイルの名前であるという事実を裏付けているようです。 これ 状態:

Argv [0]はプログラム自体のパスと名前です。これにより、プログラムは自分自身に関する情報を発見できます。また、プログラム引数の配列にもう1つ追加されるため、コマンドライン引数をフェッチする際の一般的なエラーは、argv [1]が必要なときにargv [0]を取得することです。

4
ChrisF

ISO-IEC 9899の状態:

5.1.2.2.1プログラムの起動

argcの値がゼロより大きい場合、argv[0]が指す文字列はプログラム名; argv[0][0]は、プログラム名がホスト環境から利用できない場合はヌル文字になります。 argcの値が1より大きい場合、argv[1]が指す文字列argv[argc-1]は、プログラムパラメータを表します

私も使用しました:

#if defined(_WIN32)
  static size_t getExecutablePathName(char* pathName, size_t pathNameCapacity)
  {
    return GetModuleFileNameA(NULL, pathName, (DWORD)pathNameCapacity);
  }
#Elif defined(__linux__) /* Elif of: #if defined(_WIN32) */
  #include <unistd.h>
  static size_t getExecutablePathName(char* pathName, size_t pathNameCapacity)
  {
    size_t pathNameSize = readlink("/proc/self/exe", pathName, pathNameCapacity - 1);
    pathName[pathNameSize] = '\0';
    return pathNameSize;
  }
#Elif defined(__Apple__) /* Elif of: #Elif defined(__linux__) */
  #include <mach-o/dyld.h>
  static size_t getExecutablePathName(char* pathName, size_t pathNameCapacity)
  {
    uint32_t pathNameSize = 0;

    _NSGetExecutablePath(NULL, &pathNameSize);

    if (pathNameSize > pathNameCapacity)
      pathNameSize = pathNameCapacity;

    if (!_NSGetExecutablePath(pathName, &pathNameSize))
    {
      char real[PATH_MAX];

      if (realpath(pathName, real) != NULL)
      {
        pathNameSize = strlen(real);
        strncpy(pathName, real, pathNameSize);
      }

      return pathNameSize;
    }

    return 0;
  }
#else /* else of: #Elif defined(__Apple__) */
  #error provide your own implementation
#endif /* end of: #if defined(_WIN32) */

そして、文字列を解析してパスから実行可能ファイル名を抽出するだけです。

4
Gregory Pakosz

argv[0] !=実行可能ファイル名を持つアプリケーション

  • 多くのシェルは、argv[0][0] == '-'をチェックすることにより、ログインシェルかどうかを判断します。ログインシェルにはさまざまなプロパティがあります。特に、/etc/profileなどのデフォルトファイルのソースがあります。

    通常、init自体またはgettyが先頭の-を追加します。以下も参照してください: https://unix.stackexchange.com/questions/299408/how-to-login-自動的に入力せずに、ルートユーザー名またはビルドのパスワード/ 300152#300152

  • マルチコールバイナリ、おそらく最も顕著なのは Busybox です。これらのシンボリックリンクの複数の名前。 /bin/shおよび/bin/lsを単一の実行可能ファイル/bin/busyboxに変換し、argv[0]から使用するツールを認識します。

    これにより、複数のツールを表す単一の静的にリンクされた実行可能ファイルを作成することが可能になり、基本的にすべてのLinux環境で動作します。

参照: https://unix.stackexchange.com/questions/315812/why-does-argv-include-the-program-name/315817

Runnable POSIX execve example where argv[0] !=実行可能ファイル名

他の人はexecに言及しましたが、ここに実行可能な例があります。

交流

#define _XOPEN_SOURCE 700
#include <unistd.h>

int main(void) {
    char *argv[] = {"yada yada", NULL};
    char *envp[] = {NULL};
    execve("b.out", argv, envp);
}

紀元前

#include <stdio.h>

int main(int argc, char **argv) {
    puts(argv[0]);
}

次に:

gcc a.c -o a.out
gcc b.c -o b.out
./a.out

与える:

yada yada

はい、argv[0]は次の場合もあります。

Ubuntu 16.10。でテスト済み。

それがほぼ普遍的な慣例なのか標準なのかはわかりませんが、どちらにしてもそれに従う必要があります。ただし、UnixやUnixライクなシステムの外部で悪用されることはありません。 Unix環境では(特に昔の場合は)、プログラムは、呼び出される名前によって大幅に異なる動作をする場合があります。

編集:私が他の投稿から特定の標準からのものであると誰かが特定したことを私は同時に見ますが、この規約は長い間標準に先行していると確信しています。

2
Joe Mabel

WorkbenchでAmigaプログラムを起動すると、argv [0]は設定されず、CLIのみで設定されます。

0
Polluks