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


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

効果的なC ++アイテム#3の状態「可能な限り使用することはCONST」、私は「なぜこれらの『定数』パラメータをしない考え始めますconst」?。

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


38
argcとして宣言するのは自由constです。
Oliver Charlesworth

14
:私はこれを行う多くの生産品質のコード見てきました--argc
Aniketインゲ

2
私はそれがCのレガシーに関係していると思いますが、どうしたらいいのかわかりません。
Luis Machuca 2013

13
「可能な限り常にconstを使用する」とは、参照によって渡されるものを指し、関数が終了すると関数内の変更は永続化されると思います。これは、整数のように値で渡されるものには当てはまりません。そのため、それを作成しても何も得られませんconst。実際、手段argcとして渡すと、たとえば関数内でカウンタとしてconst int使用できなくなりますargc
スティーブ・メルニコフ2013

4
@SteveMelnikoff:const値渡しのパラメーターを作成しても何も得られないことに同意しません。例えば参照stackoverflow.com/a/8714278/277304stackoverflow.com/a/117557/277304
leonbloy

回答:


114

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

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

(余談ですが、興味深いことに、getopt'のプロトタイプでは変更されないargv[]ものの、指定された文字列は変更される可能性がありますが、Linuxのマニュアルページでは、getoptその引数が入れ替えられていることを示しています。グループはこの順列については言及していません。)

パッティングconstargcargv多くを購入しないだろう、それはのようないくつかの古い学校のプログラミングプラクティスを、無効になります。

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

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


1
-1 Re「getoptなどの一部のUNIX APIは実際にはargv []を操作するため、その理由でconstにすることもできません。」トップレベルconstを自由にに追加でき、argvC関数の機能に影響を与えません。また、getoptとして宣言されint getopt(int argc, char * const argv[], const char *optstring);ます。そして、ここでconstはトップレベルではありませんが、ポインタをconst変更しないことを約束していることを宣言しています(ただし、それらが指す文字列は変更される可能性があります)。
乾杯とhth。-Alf

Cheersandhth.-アルフ@:getopt 並べ替えるargv[]デフォルトでは、配列を、しかし、文字列を変更しません。(permuteという単語は、manページから直接来ています。)つまり、argv配列自体はconst、それが指す文字列が存在する場合でもそうではないということです。argv[]配列を並べ替えて操作しないのはなぜですか?
Joe Z

1
申し訳ありませんが、私が見たドキュメントには一貫性がありません。署名はそのような順列を許可していません。例を参照してください。ただし、次のテキストは、置換することを示しています。それで、私は反対票を取り除いています。
乾杯とhth。-Alf

1
つまり、私は反対投票を削除できるように、「ロック解除」するためにいくつかの編集を行う必要があります。いいえ、プロトタイプを誤解しています。私が提供した例とコンパイルエラー「読み取り専用ロケーションの割り当て」を見てください。
乾杯とhth。-Alf

1
@ Cheersandhth.-Alf:おもしろい...ヘッダーでプロトタイプを調べたところ、char* const* ___argvそこにありましたが、インターフェースは実際にはに準拠していconst char **ます。そのような混乱。私はの優先混乱していた[]*に関してconst。謝罪いたします。
Joe Z

36

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

5.1.2.2.1プログラムの起動

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

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

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

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

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

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

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

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

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


面白い。半関連のメモで、QtのQApplication(argc,argv)コンストラクターargcreferenceで定義されているためにクラッシュの原因となるバグに遭遇しました。それには驚きました。
HostileForkはSEを信頼してはならないと2013

23

argcmain()pre-datesの関数シグネチャのため、通常は定数ではありませんconst

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

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


8

const仮引数の最上位は関数型の一部ではありません。好きなように追加したり削除したりできます。これは、関数の実装で引数を使用して実行できることにのみ影響します。

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

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


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


要約すると、に追加constすることを妨げるものは何もありませんargcが、で最も有用なconst-ness argvは非標準のmain関数を提供し、おそらくそのように認識されません。幸いにも(皮肉な方法で)、移植可能な真剣なコードに標準の引数を使用ないことには十分な理由がありmainます。非常に簡単に言えば、実際には、それらは英語のアルファベット文字のみで、古いASCIIのみをサポートします。


1
cygwinまたはUTF-8を適切にサポートする別のlibcを使用してWindows用に開発している場合(私が知る限り、cygwinは現在のところ唯一のものですが、別のオプションで作業している人がいます)、標準のmain署名は正常に機能し、次のことができます。任意のUnicode引数を受け取ります。
R .. GitHub ICE HELPING ICE STOP

@Rそれらはまた、ほとんどの* nixプラットフォームでも正常に動作します。問題は、それらが機能するプラットフォームがあるかどうかではありません。しかし、非常に素晴らしいイニシアチブです。そして、たまたま同じように真剣に取り組んでいます
乾杯とhth。-Alf

4

の署名mainは、やや歴史的な遺物ですC。歴史的にC持っていませんでしたconst

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


「historical C」と言ったとき、ここでどのくらい歴史的な話をしているのですか。
ジョーZ

8
constC89 / C90に追加されました。それに先立って、それはCの一部ではなかった
ジョナサン・レフラー

@JonathanLeffler:ご存知のとおり、私はそれを忘れていました。私は1992年にCを学びました。それ以前は、パスカル、ベーシック、およびアセンブリハッカーでした。
ジョーZ

2

そのためargc、ローカル変数である(そして、C ++、ない参照か何かで)、との特別な場所ので、main後方互換性の悪さがに無い魅力的な理由でそれを余裕の膨大な量を与えることを意味し、それがCONSTにするアプリケーション。

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) {}

明示的な戻り値型のないバリアントは、C11はもちろんのこと、C99ではもはや有効ではないことに注意してください。ただし、コンパイラーは、下位​​互換性のために引き続き許可しています。C ++コンパイラーは、戻り値のないバリアントを受け入れるべきではありません。
ジョナサンレフラー

@JonathanLefflerうん、それでも最後のideoneの例(ideone.com/m1qc9c)はG ++ 4.8.2 with -std=c++11です。Clangもそれを受け入れますがwarning: only one parameter on 'main' declaration [-Wmain]、を与えます。MSVCは、欠落している戻り型指定子とargcへの参照の欠如についてのみ抗議します。繰り返しますが、 'shenanigans'と '
leeway

1

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

独自の関数と関連するプロトタイプを定義するとき、どのパラメーターを作成でき、どのパラメーターがconst関数によって変更されるかがわかります。

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

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.