CまたはC++アプリケーションでmain()
に引数を渡すと、argv[0]
は常に実行可能ファイルの名前ですか?または、これは単なる一般的な慣習であり、常に100%真実であるとは限りませんか?
推測作業(教育を受けた推測作業でも)は楽しいものですが、確かに標準文書にアクセスする必要があります。たとえば、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でさえ、それを文書化する必要があります。
exec*()
呼び出しを持つ*nix
型システムでは、argv[0]
は、呼び出し元がexec*()
呼び出しのargv0
スポットに置くものになります。
シェルは、これがプログラム名であるという規則を使用しており、他のほとんどのプログラムは同じ規則に従っているため、argv[0]
は通常プログラム名です。
しかし、不正なUnixプログラムはexec()
を呼び出してargv[0]
を好きなように作成できるため、C標準が何を言おうとも、この100%の時間を当てにすることはできません。
C++標準のセクション3.6.1によると:
argv [0]は、プログラムまたは「」を呼び出すために使用される名前を表すNTMBSの最初の文字へのポインタです。
いいえ、少なくとも標準では保証されていません。
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) */
そして、文字列を解析してパスから実行可能ファイル名を抽出するだけです。
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環境では(特に昔の場合は)、プログラムは、呼び出される名前によって大幅に異なる動作をする場合があります。
編集:私が他の投稿から特定の標準からのものであると誰かが特定したことを私は同時に見ますが、この規約は長い間標準に先行していると確信しています。
WorkbenchでAmigaプログラムを起動すると、argv [0]は設定されず、CLIのみで設定されます。