2016-01-30 26 views
8

最近(2016年1月、質問が長引く場合は)質問Are the strings in argv modifiable?がありました。コメント欄で
thisの答えに、(2501 @およびI)、我々はそれが本当に文字の文字列(例えば、文字が**argvである)それは修正可能ですか文字列にポインタ(例えば、ポインタされているかどうかを主張しました*argv)。適切な標準引用はC11標準草案N1570であるargvの文字列へのポインタは変更可能ですか?

、§5.1.2.2.1/ 2:

パラメータargcargvと文字列はによってMODI Fiができなければならない argvアレイによって指さプログラムの起動とプログラム終了の間に最後に格納された値を保持します。

argvが指す文字列へのポインタは変更可能ですか?

+0

'argv'は変更可能であり、' argv'はあなたが話すポインタを含んでいます。 –

+0

@SimonShineしかし、 'argv'が変更可能な場合、' argv = ... 'のみが実行可能であり、必ずしも' * argv = ... 'ではないという意味ですか? – Downvoter

+0

適切な 'main'関数宣言の1つが' int main(int argc、char * argv []) 'であるため、' argv'パラメータは 'char *'ポインタではなく 'char * argv [] 'ポインタ。したがって、文字列は変更可能です。 – nsilent22

答えて

6

質問で引用されているように、C11標準では、argcargvという変数と、argvの配列が指す文字列が変更可能であることが明示的に記載されています。これらのポインタが変更可能であるかどうかは、手元の問題です。標準は明示的にそれを一方向または他の方法で述べていないようです。

2つのキーポイントは、標準で言葉遣いについて注意することがあります。

  1. ポインタが不変であることをなっていた場合は、標準は、int main(int argc, char *const argv[])として宣言することが主な要求することにより、それは明らかにされている可能性がこの質問に対する別の回答ではhaccks mentionedとなります。

    argvに関連して言及されたconstであるという事実は意図的であると思われる。つまり、constの欠如はオプションではありませんが、標準によって決定されます。

  2. 標準では、常にargvが配列を呼び出します。配列の変更とは、メンバの変更を指します。したがって、標準の文言は、argvが変更可能であると述べたときにargv配列内のメンバーを変更することを意味することは明らかです。

    一方、(C11ドラフトN1570、§6.7.6.3p7に基づいて)C の配列パラメータ「と 『入力する修飾ポインタ』に調整しなければなりません」。 xyは、それぞれ、int *xint *yに調整されているのでこのように、次のコード、

    int foo(int x[2], int y[2]) 
    { 
        if (x[0] > y[0]) 
         x = y; 
        return x[1]; 
    } 
    

    は、有効C11です。 (これはまた、C11ドラフトN1570、§6.3.2.1p3:"...配列で繰り返されています...「...配列の最初の要素を指すことを「型へのポインタ」型の表現に変換される。) もちろん、同じことは、ローカルまたはグローバル配列として宣言されていないしxy場合、ではないであろうそれは、ポインタがあまりにも修正する必要があります。したがって、答えとして意味が関数のパラメータ。

は限り言語lawyerismが行くように、私は、標準はそれを一つの方法または別のを述べていないと言うだろう〜OP:両方


実際には、argv配列内のポインタの変更可能な伝統は非常に長いです。多くのライブラリには、argcへのポインタとargv配列へのポインタを取る初期化関数があり、そのうちのいくつかはargv配列のポインタを変更します(ライブラリ固有のオプションを削除します)。例えばGTK+ gtk_init()MPI_Init()です(少なくともOpenMPIでは明示的にそれを調べたり変更しないと明言していますが)。パラメータ宣言(int *argc, char ***argv)を探します。唯一の理由は、を使用してmain()から呼び出すことを意図している場合は、ポインタを変更して、ライブラリ固有のコマンドラインパラメータを解析してコマンドラインパラメータから削除し、argcとポインタは必要に応じてargvにあります。

(私はもともとPOSIX getopt()施設は変更可能で、ポインタにを依存していると述べている - ほとんどのUnixのフレーバーで採択されたバック1980年にさかのぼる機能を、そして1997年にPOSIX.2で標準化 - しかし、それはありますジョナサン・レフラーはコメントで指摘したように、誤っ、:;だけGNU getopt()はありません、それはPOSIXLY_CORRECT環境変数が設定されていない場合にのみ、両方GNU getopt_long()とBSDはgetopt_long()ポインタを変更POSIXLY_CORRECTが設定されていない限り、POSIX getopt()は、実際のポインタを変更しません。しかし、それらはgetopt()と比較してはるかに若く、広範ではない。

Unixの土地では、argv[]配列、が指す文字列の内容を変更し、変更された文字列がプロセスリストに表示されるように、 "移植可能"とみなされました。これがどのように役立つかの一例は、DJBのdaemontoolsパッケージreadproctitleです。 (文字列はインプレースで変更する必要があり、変更をプロセスリストに表示するには拡張できません)。

これは、C言語の誕生以来、プログラミング言語として、Cの標準化に先立ち、argc,argvargv配列のポインタ、およびこれらのポインタが指す文字列の内容を変更可能なものとして扱うことができます。

C標準の目的は、新しい動作を定義するのではなく、(移植性と信頼性を促進するために)既存の動作をコード化しているためです。 argv配列内のポインタを変更可能として明示的に指定しないようにすることができます。それ以外のものは伝統を破り、POSIX規格(システム間の移植性を促進することを目的としており、ISO C標準には含まれていないCの機能を拡張することを意図している)とは明らかに反するでしょう。

+0

標準 'getopt()'は変更可能な 'argv'に依存しません。 GNUの 'getopt()'は引数リストを置換するためです。 –

+0

@JonathanLeffler:まあ、本当!私は古いUnixのgetopt()実装のいくつかをチェックして、引数リストをそのまま残していました。 GNUの 'getopt()'のみがポインタを変更します。 (しかし、 'POSIXLY_CORRECT'環境変数がセットされていなければ、GNUとBSDの' getopt_long() 'はポインタを*' const'とマークされていても変更します)。 –

+0

@JonathanLefflerによって指摘された 'getopt()'についての誤った部分を、GTK +とMPI初期化関数(そして他のライブラリ初期化関数を探すことができる署名)で置き換えました。あなた(または他の誰か)が他のエラーを見つけたら、それらを指摘してください。 –

1

ポインタが変更可能かどうかは、ポインタのconstnessに依存します。パラメータargvは、char *argv[]またはchar **argvと宣言されています。それは彼らがchar *const argv[]として扱うかどうか(私は気づいていません)環境に依存します。

+3

しかし、あなたは実際にポインタが書き込み可能であるというステートメントを 'const'でないことから知ることができますか?この質問に[私のコメント](http://stackoverflow.com/questions/35105918/are-the-pointers-to-strings-in-argv-modifiable?noredirect=1#comment57932896_35105918)を参照してください。 @cad; – Downvoter

+0

;あなたはポインタの修正について質問しましたが、指している内容ではありません:* 'argv'の文字列へのポインタは変更可能ですか?*。 'char const * a'と' char * const a'はどちらも意味が異なります。 – haccks

+1

しかし、答えの最初の2つの文は私に何を教えてくれるのですか?基本的に、文字列へのポインタは、それに応じて宣言されるため、変更可能です。つまり、実装によっては変更可能だと言いますか? – Downvoter

関連する問題