重複の可能性:
main 関数のコマンドライン引数について
C の main(int argc, char* argv) に渡すことができるデータの最大サイズをどのように判断しますか? これを定義する標準のどこかにマクロはありますか? データはメイン プロセスによって「所有」されていますか (つまり、私のプログラムはこのデータを保存しますか)、それともオペレーティング システムによって何らかの形で「所有」されており、そのデータへのポインタを取得できますか?
重複の可能性:
main 関数のコマンドライン引数について
C の main(int argc, char* argv) に渡すことができるデータの最大サイズをどのように判断しますか? これを定義する標準のどこかにマクロはありますか? データはメイン プロセスによって「所有」されていますか (つまり、私のプログラムはこのデータを保存しますか)、それともオペレーティング システムによって何らかの形で「所有」されており、そのデータへのポインタを取得できますか?
POSIX システムでは、最小許容値(4096)ARG_MAX
で定義された値 があります。パラメーターを使用して関数を介して、実行時に値を検出できます。<limits.h>
_POSIX_ARG_MAX
sysconf()
SC_ARG_MAX
多くの場合、256 KiB です。
データargv
(ポインターの配列とそれらが指す文字列の両方) は、プログラムによって「所有」されます。それらは変更できます。それが賢明かどうかは、あなたの見方次第です。main()
未定義の動作を呼び出さずに、関数に渡されたものの境界の外に出ることは確かにできません。GNU などの関数getopt()
は、環境で POSIXLY_CORRECT 環境変数を設定せずに実行すると、引数を再編成します。argv
as provided to内のデータへのポインタが既にありますmain()
。
経験的に、文字列の末尾の直後のデータargv[argc-1]
が実際には環境の開始点であることがよくあります。メイン プログラムはint main(int argc, char **argv, char **envp)
、一部のシステム (C 標準付属書 J、§J.5.1 の拡張として認識されている) のenvp
ように記述できenviron
ます。環境文字列へのポインターの配列。
ARG_MAX
新しいプロセスの引数の最大長です
あまりにも多くの引数を指定してプログラムを呼び出そうとした場合、つまりパターン マッチングに関連して、次のエラー メッセージが表示されます。
$ command *
exec()
このエラーが発生するのは、システム コールとその直接のバリアントだけです。それらは、対応するエラー状態 E2BIG () を返します。
シェルのせいではありません。このエラーが表示されるだけです。実際、ここでは exec() はまだ必要ないため、シェルの拡張は問題ではありません。拡張は、仮想メモリ システム リソースによってのみ制限されます。
したがって、次のコマンドはスムーズに機能します。これは、新しいプロセスにあまりにも多くの引数を渡す代わりに、シェルの組み込み (echo) を使用するか、制御構造を使用して引数を反復処理する (for ループ) ためです。
/dir-with-many-files$ echo * | wc -c
/dir-with-many-files$ for i in * ; do grep ARG_MAX "$i"; done
上限を知るにはさまざまな方法があります
コマンド: getconf ARG_MAX
システムコール: sysconf(_SC_ARG_MAX)
システム ヘッダー: <[sys/]limits.h> などの ARG_MAX
sysconf
ヘッダーとは対照的に、getconf
実際に有効な制限を伝えます。これは、再構成、再コンパイル (Linux など)、またはパッチの適用 (HP-UX 10) によって実行時に変更できるシステムに関連しています。
の使用例sysconf()
:
#include <stdio.h>
#include <unistd.h>
int main() {
return printf("ARG_MAX: %ld\n", sysconf(_SC_ARG_MAX));
}
cpp がインストールされている場合、ヘッダーの制限を見つける便利な方法:
cpp <<EOF
#include <limits.h>
#include <param.h>
#include <params.h>
#include <sys/limits.h>
#include <sys/param.h>
#include <sys/params.h>
arg_max: ARG_MAX
ncargs: NCARGS
EOF
ARG_MAX
/を見るときは、と(引数と環境)NCARGS
の両方によるスペース消費を考慮する必要があります。したがって、現在使用可能なスペースを適切に見積もるためには、少なくとも ARG_MAX の結果を減らす必要があります。argv[]
envp[]
env|wc -c
env|wc -l * 4
POSIX は、プロセスがその環境を安全に変更できるように、さらに 2048 を減算することを提案しています。getconf コマンドによる簡単な見積もり:
expr `getconf ARG_MAX` - `env|wc -c` - `env|wc -l` \* 4 - 2048
現在使用可能なスペースを取得する最も信頼できる方法は、失敗するまで引数の長さを増やして exec() の成功をテストすることです。これはコストがかかるかもしれませんが、少なくとも一度だけチェックする必要があり、envp[] の長さは自動的に考慮され、結果は信頼できます。
代わりに、GNU autoconf チェック「コマンドライン引数の最大長をチェックしています...」を使用できます。それは非常によく似た働きをします。
ただし、意図的にも簡単にするためにも、はるかに低い値になります (実際の値の 4 分の 1 になる可能性があります)。
n が増加するループでは、チェックは引数の長さが 2n の exec() を試行します (ただし、16 より大きい n、つまり 512kB はチェックしません)。ARG_MAX が 2 の累乗の場合、最大値は ARG_MAX/2 です。最後に、「C++ コンパイラは大量の追加引数を追加できる」という理由で、見つかった値を (安全のために) 2 で割ります。
実際の値
Linux 2.6.23 では、スタック サイズの 1/4 です。参考までにカーネルコード。
main()
受け入れるものに関しては特別ではありません。main()
特別なのは、最初に呼び出される前に発生する魔法です。
好きなように呼び出すことができますmain()
...
#include <stdio.h>
char longstring[1024000] = "foo";
int main(int argc, char **argv) {
char *p = longstring;
printf("main called with argc == %d", argc);
if (argv) printf(" and a relevant argv");
puts("");
switch (argc) {
case 1: main(2, NULL); break;
case 2: main(3, &p); break;
default: puts("Uff!"); break;
}
return 0;
}
私が間違っているかもしれませんが、argc と argvはlibc.so.6の__libc_start_mainに属していると思います。
役立つかもしれません:)