web-dev-qa-db-ja.com

argcが定数ではないのはなぜですか?

int main( const int argc , const char[] const argv)

有効なC++ Item#3は「可能な限りconstを使用する」と述べているので、「これらの「定数」パラメータをconstにしない理由」を考え始めます。

プログラムでargcの値が変更されるシナリオはありますか?

102
Dinushan

この場合、履歴が要因です。 Cはこれらの入力を「一定ではない」と定義し、既存のCコード(の大部分)との互換性がC++の初期の目標でした。

getoptなどの一部のUNIX APIは実際にargv[]を操作するため、そのためにconstにすることはできません。

(さておき、興味深いことに、getoptのプロトタイプはargv[]を変更しないが、指定された文字列を変更する可能性があることを示唆しているが、Linuxのmanページはgetopt彼らは自分がいたずらしていることを知っているようだ 。Open Groupのmanページでは、この置換については言及されていません。)

constargcargvを置くことはあまり買わず、次のような旧式のプログラミングプラクティスを無効にします。

// print out all the arguments:
while (--argc)
    std::cout << *++argv << std::endl;

私はそのようなプログラムをCで書いていますが、私は一人ではないことを知っています。 somewhereから例をコピーしました。

113
Joe Z

C規格(ISO/IEC 9899:2011)は次のように述べています:

5.1.2.2.1プログラムの起動

¶1プログラムの起動時に呼び出される関数の名前はmainです。実装は、この関数のプロトタイプを宣言しません。戻り値の型intでパラメーターなしで定義されます。

int main(void) { /* ... */ }

または2つのパラメーター(ここではargcおよびargvと呼びますが、宣言されている関数に対してローカルであるため、任意の名前を使用できます):

int main(int argc, char *argv[]) { /* ... */ }

または同等のもの;10) または他の実装定義の方法で。

¶2宣言されている場合、main関数へのパラメーターは以下の制約に従います:

  • argcの値は非負でなければなりません。
  • argv[argc]はNULLポインターでなければなりません。
  • argcの値がゼロより大きい場合、配列メンバーargv[0]argv[argc-1]には、プログラムの前にホスト環境によって実装定義の値が与えられる文字列へのポインターが含まれます。起動。その目的は、ホストされた環境の他の場所からプログラムを起動する前に決定された情報をプログラムに提供することです。ホスト環境が大文字と小文字の両方で文字を含む文字列を提供できない場合、実装は文字列が小文字で受信されることを保証する必要があります。
  • argcの値がゼロより大きい場合、argv[0]が指す文字列はプログラム名を表します。プログラム名がホスト環境から利用できない場合、argv[0][0]はヌル文字でなければなりません。 argcの値が1より大きい場合、argv[1]からargv[argc-1]が指す文字列はプログラムパラメーターを表します。
  • パラメータargcおよびargvおよびargv配列が指す文字列は、プログラムで変更可能であり、プログラムの起動と終了の間で最後に保存された値を保持します。

10) したがって、intintとして定義されたtypedef名に置き換えることができます。また、argvのタイプはchar **argvなどとして記述することができます。

最後の箇条書きに注意してください。 argcargvの両方を変更可能にする必要があると書かれています。変更する必要はありませんが、変更することができます。

36

argcは、main()の関数シグネチャがconstに先行するため、通常は定数ではありません。

Argcはスタック変数であるため、変更しても独自のコマンドライン処理以外には影響しません。

もちろん、必要に応じてconstを自由に宣言できます。

23
razeh

仮引数のトップレベルconstは、関数型の一部ではありません。好きなように追加したり削除したりできます:関数実装の引数でできることだけに影響します。

したがって、argcにはconstを自由に追加できます。

ただし、argvの場合、関数シグネチャを変更せずに文字データconstを作成することはできません。つまり、標準のmain関数シグネチャの1つではなく、main関数として認識される必要はありません。だから、良いアイデアではありません。


おもちゃ以外のプログラムで標準のmain引数を使用しないのは、Windowsでは国際文字を含むファイル名などの実際のプログラム引数を表現できないためです。これは、WindowsではWindows ANSIとしてエンコードされた非常に強力な規則によるためです。 Windowsでは、GetCommandLine AP​​I関数の観点から、より移植性の高い引数アクセス機能を実装できます。


まとめると、constargcに追加することを妨げるものは何もありませんが、constの最も有用なargv- nessは、非標準のmain関数、おそらくそのように認識されません。幸いなことに(皮肉な方法で)使用しない移植性のある深刻なコードの標準main引数には正当な理由があります。簡単に言うと、実際には、古いASCIIのみをサポートし、英語のアルファベット文字のみをサポートしています。

mainのシグネチャは、Cからの歴史的なアーティファクトです。歴史的にCにはconstがありませんでした。

ただし、constの効果はコンパイル時のみであるため、パラメーターconstを宣言できます。

4
George

argcはローカル変数(およびC++では、参照などではない)であり、mainの特別な場所は、下位互換性のシェナンガンが、 forceアプリケーションを強制する理由として説得力があります。

main() {}

int main() {}

main() { return 0; }

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

int main(const int argc, const char** argv) { /* no return*/ }

これらおよび他の多くのバリエーションは、広範囲のCおよびC++コンパイラでコンパイルされます。

したがって、最終的にはargcがconstではないということではなく、必ずしもそうである必要はありませんが、必要に応じてそうすることができます。

http://ideone.com/FKldHF 、Cの例:

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

http://ideone.com/m1qc9c 、C++の例

main(const int argc) {}
2
kfsone

歴史的な理由とは別に、argcとargvをconst以外に保つ良い理由は、コンパイラーの実装がmainの引数で何をしようとしているのかわからないということです。

独自の関数と関連するプロトタイプを定義するとき、constを作成できるパラメーターと、関数が変更するパラメーターを知っています。

極端に言えば、すべての関数のすべてのパラメーターをconstとして宣言する必要があることを宣言し、それらを変更する理由がある場合(たとえば、配列を検索するためにインデックスをデクリメントする場合)、 const変数を使用し、const引数の値をそれらの変数にコピーします。これにより、忙しい作業や余分なLOCを実現できますが、実質的なメリットはありません。引数の値を変更していない場合は、適切な静的アナライザーが検出します。パラメーターをconstにすることをお勧めします。

1
Sam Skuce