配列のインデックスとargc signedness
質問
の C標準規格 (5.1.2.2.1プログラムの起動)言うのです:
機能の呼び出プログラムの起動 名主なものです。 [...]
ほかの例外をラップしている可能として定義され 戻り値の型のintとのない パラメータ:
int main(void) { /* ... */ }
またはその二つのパラメータ [...] :
int main(int argc, char *argv[]) { /* ... */ }
以降は
価値のargcは負でない.
- なぜ な
argc
定義することとしてunsigned int
,argc
とを意味する"引数count'? - すべ
argc
使用する指標としてargv
?
になろうかと迷った場合は、Cを標準というものの型の配列のインデックス.で署名?
6.5.2.1配列subscripting:
一つの表現はタイプ "ポインタをオブジェクトタイプ"、その他 表現は、 整数型, とその結果タイプ"タイプ’’.
いまそのsignednessはなかったの探しています)。いかにしてつくられているのかを見るコードをネガ配列数array[-1]
がないので未定義的に振る舞えるのでしょうか?
- は配列の指号付き(符号なし?
解決
メインのint()理由は歴史的なもの - それは常に長い言語が標準化された前から、そのようになっています。配列インデックスの要件は、それが配列(またはいくつかの状況では、エンド過去1)の範囲内であることである - 何か他のものは不定であるため、符合は重要ではない
。他のヒント
1)についてのmain()のargcタイプ:私見標準が(30年以上)非常に古い伝統を守り続け、そして今...それは単純なもの(注変更するには遅すぎます。ほとんどのシステムでもないコンパイラでは、でも「のargcは」「符号なし」に定義されている場合、リンカ、またCPUが文句を言うだろうが、あなたは規格外です!)
2)の実装の大部分に[ARGC]合法であり、NULLに評価argvを。実際、引数リストの終わりを見つけるための別の方法は、ARGV [i]がNULLである場合に0終端からのargvに反復することである。
3)負の数と配列/ポインタ演算は限り(P-N)からpまでのアドレス範囲が同じメモリオブジェクトに属するように合法です。即ちあなたが持つことができます。
char array[100];
char *p;
p = &array[50];
p += -30; /* Now p points to array[20]. */
得られたポインタは依然として元のメモリ・オブジェクト(「アレイ」)の内側に留まるので、ポインタ演算のこの使用は合法です。ほとんどのシステム上でポインタ演算は、このルールに違反してメモリに移動するために使用することができ、それは完全にシステムに依存なので、これは移植可能ではありません。
Cで一般に、「少なくとも驚きの原理は、」符号なしであるために十分な理由がない限り変数が署名することが好ましいことを意味します。あなたは符号付きと符号なしの値を混在させると、タイプのプロモーションルールが予期しない結果につながることができますので、これは次のとおりです。argc
が署名した場合などは、この単純な比較は驚くべき結果につながるます:
if (argc > -1)
(その値はほぼ確実に大きく-1
よりなる、unsigned int
に変換されるようUINT_MAX
は、argc
が促進される)。
1)ARGCは、あなたがどのargv[0]
プログラム名の前に引数を付加することができますどのように、引数の数であるが、非常に正直に言うと。それは無意味であるとして、あなたは単にあなたが「args1」でしょうfoo
としてargs1 foo args2
の符号付きの型、すなわち、そのようなものであることargc
にもかかわらず、int
を言うことができない、argv[-1]
と呼ばれるプログラムを想像して...
argv[0]
、オフセットzero'thに実行可能プログラム名を詰め込むように、 2)の理由argcが本当に引数ベクトル(したがって、「のARGVの」)へのインデックスではありませんargc
は1でオフになります。
3)配列インデックスは、ポインタ操作の点で、の を提供あなたは、ポインタが陰性と配列の添字を使用して、にあるメモリのブロックの境界内にあります配列の添字は、彼らがしていることだけでは可換例えば、
ポインタのショートカットであり、ないと合法ですchar v[100]; char *p = &v[0]; You can do this: p[55] = 'a'; Which is the same as *(p + 55) = 'a'; You can even do this: p = &v[55]; p[-10] = 'b' /* This will stuff 'b' into 45'th offset! */ Which is the same as *(p - 10) = 'b';それは未定義の動作で、それを処理する方法については、実行時の実装に依存し、おそらくセグメンテーション違反、またはプログラム -
また、あなたは、このような境界の外にあるように、配列を使用して操作した場合クラッシュ....
4)* nixの環境では、いくつかは、再び、これはめったにDOS / Windowsのマイクロソフトの世界で使用されていない主なchar **endvp
に供給される第3のパラメータを、持っているでしょう。いくつかの* nixのランタイム実装は、事前に歴史的な理由のために、あなたは実行時を経て、環境変数で渡すことができます。