二つの引数を取るsizeof
-
27-10-2019 - |
質問
C++のC.1.3では(2003。それはC++11にもあります)、標準はISO CとC++の違いを指摘しています;すなわち、
char arr[100];
sizeof(0, arr)
戻り値 sizeof(char*)
Cでは、しかし 100
C++で。
私はのための文書を見つけることができません sizeof
二つの引数を取ります。明らかなフォールバックはコンマ演算子ですが、私はそうは思わない: sizeof(arr)
Cでは 100
; sizeof(0, arr)
は sizeof(char*)
.両方 sizeof(0, arr)
と sizeof(arr)
は 100
C++で。
この文脈では、ISの全体のポイントが欠落している可能性があります。誰でも助けることができますか?これは09年に議論された質問に似ていますが、誰もISに言及しておらず、正しい答えが与えられたとは思いません。
編集:実際には、isはコンマ演算子について話しています。だから、何らかの理由で (0, arr)
aを返します char*
Cでは、しかしa char[100]
C++で。どうして?
解決
Cでは、右辺値と左辺値に関連するコンマ演算子の仕様が異なるため、配列はポインタに減衰しています(そのような違いが見つかるのは唯一の場C++では、配列は配列のままであり、正しい結果が得られます。
他のヒント
Cでは、コンマ演算子は左辺値を生成せず、その結果、配列は左辺値を生成しません arr
これは左辺値です 崩壊 (この場合は)右辺値であるポインタ型に。だから sizeof(0,arr)
と同等になります sizeof(char*)
, のために、 左辺値から右辺値へ 変換。
しかし、C++では、コンマ演算子は左辺値を生成します。いいえありません 左辺値から右辺値へ 変換。だから sizeof(0,arr)
同じままであり、これは次のものと同等です sizeof(char[100])
.
ところで, sizeof
関数ではなく、演算子です。したがって、以下は完全に有効なC++(およびc、あなたが想像すれば printf
の代わりに cout
):
int a[100], b[200], c[300], d[400];
cout << sizeof(a,b,c,d) << endl;
デモ : http://www.ideone.com/CtEhn
あなたは私が4つのオペランドを渡したと思うかもしれません sizeof
しかし、それは間違っています。 sizeof
上で動作します その結果 コンマ演算子の。そして、その理由は、多くのオペランドを参照してください多くのコンマ演算子の。
4つのオペランドと3つのコンマ演算子;ちょうどのように 1+2+3+4
, 、3つの演算子、4つのオペランドがあります。
上記は次のものと同等です(C++0xで有効):
auto & result = (a,b,c,d); //first all comma operators operate on the operands.
cout << sizeof (result) << endl; //sizeof operates on the result
デモ : http://www.ideone.com/07VNf
だからそれは コンマ あなたを作る演算子 感じる 多くの人がいること 引数.ここに コンマ は演算子ですが、関数呼び出しでは, コンマ は演算子ではなく、単に引数の区切り文字です。
function(a,b,c,d); //here comma acts a separator, not operator.
だから sizeof(a,b,c,d)
上で動作します タイプ の結果の ,
演算子は、まったく同じ方法で, sizeof(1+2+3+4)
上で動作します タイプ の結果の +
演算子。
また、あなたに注意してください できません 書き込み sizeof(int, char, short)
, 正確には、 コンマ オペレータは操作できません タイプ.それは動作します 値 のみ。私は思う, sizeof
は、cおよびC++の唯一の演算子であり、動作することができます タイプ 同様に。C++では、操作できる演算子がもう1つあります タイプ.その名前は typeid
.
これはコンマ演算子です。そして、あなたが話している違いは絶対に何の関係もありません sizeof
.違いは、実際には左辺値から右辺値、配列からポインタ、およびC言語とC++言語の間の同様の減衰動作にあります。
この点でC言語はむしろトリガーに満足しています:配列は実質的にすぐにポインタに減衰します(ごく少数の特定のコンテキストを除いて)。 0, arr
式は持っています char *
タイプ。これは次のものと同等です 0, (char *) arr
.
C++言語では、配列は"配列性"をはるかに長く保持します。のコンテキストで使用される場合 ,
演算子配列はポインタに減衰しません(左辺値は右辺値に減衰しません)。 0, arr
式はまだです char[100]
.
これは違いを説明するものです sizeof
その例での動作。 ?:
演算子は、減衰挙動の同様の違いを示す演算子の別の例です。 sizeof(0 ? arr : arr)
CとC++では異なる結果が得られます。基本的に、それはすべて、C演算子が通常、オペランドの左辺値を保持しないという事実に由来します。この動作を実証するために多くの演算子を使用できます。
これはそうではありません sizeof
二つの引数を取ります。 sizeof
は演算子であり、関数ではありません。
それを考えてみましょう (0, arr)
はコンマ演算子を使用した式であり、他のすべてが所定の位置に落ちます。
sizeof
二つの引数を取りません。しかし、それはどちらか、機能ではありません,
だから、 (...)
関数の引数を区切るのではなく、単に
構文のオプション部分、およびグループ化を強制します。あなたが書くとき
sizeof(0, arr)
, 、への引数 sizeof
は単一の式です 0,
arr
.コンマ演算子を持つ単一の式で、次の式を評価します
コンマの左側にある式は、その値をスローします(ただし、その値はスローしません
副作用)、コンマの右側にある式を評価します,
そして、その値を完全な式の値として使用します。
私はCについてはよくわかりませんが、これはcの違いかもしれません
ランゲスC++では、配列からポインタへの変換は次の場合を除き発生しません
それは必要です;Cでは、私が正しく思い出すと、標準はそれを言っています
特定の状況を除いて常に行われます。として含む
の演算子 sizeof
.この場合、コンマ演算子はそうではないので
そのオペランドの型に関して制約を持っている、
配列からポインタへの変換はC++では行われません。Cでは、
コンマ演算子のoperatandは例外にリストされていないので、
配列からポインタへの変換が行われます。(この場合、配列は
はコンマ演算子のオペランドであり、コンマ演算子のオペランドではありません sizeof
.)
ここで何が起こっているのかを確認する最良の方法は、標準の文法を見ることです。ドラフトC99標準のセクションを見ると 6.5.3
単項演算子 パラグラフ 1 sizeofの文法は次のようになっていることがわかります:
sizeof unary-expression
sizeof ( type-name )
だから、第二のものは適用されませんが、どのように sizeof unary-expression
この場合に適用されますか?私たちはセクションを見れば A.2.1
式 ドラフト標準から、次のような文法を介して作業します:
unary-expression -> postfix-expression -> primary-expression -> ( expression )
私たちは、周りの括弧を取得します 式 そして今、私たちはちょうどのための文法を見ている コンマ演算子 セクションから 6.5.17
コンマ演算子 そして、私たちは見る:
expression:
assignment-expression
expression , assignment-expression
だから我々は今持っている:
sizeof( expression , assignment-expression )
^
|
comma operator
両方 式 と 代入式 私達をに連れて行くことができます プライマリ式 これは次の文法を持っています:
primary-expression:
identifier
constant
string-literal
( expression )
と 0
である。 定数 と arr
である。 識別子 だから私たちは持っています:
sizeof( constant , identifier )
だから何をしますか コンマ演算子 ここでやる?セクション 6.5.17
パラグラフ 2 言っています:
コンマ演算子の左オペランドは、void式として評価されます;があります。 その評価後のシーケンスポイント。次に、右オペランドが評価されます;結果にはその型と値があります。97)
コンマ演算子は、配列がポインタに変換されない例外の1つではないため、ポインタ(これはセクションでカバーされています 6.3.2.1
左辺値、配列、および関数指定子)ということは、私たちが終わることを意味します:
sizeof( char * )
で C++ 文法はかなり似ているので、同じ場所で終わりますが、コンマ演算子の動作は異なります。C++ドラフト標準セクション 5.18
コンマ演算子 言っています:
[...]結果の型と値は、右オペランドの型と値です;結果は、その右オペランド[と同じ値カテゴリになります。..]
だからと 配列からポインタへ 変換は必要ありませんので、我々はで終わる:
sizeof( char[100] )
すでにいくつか述べたように、私は1つだけ追加したいと思いますが、sizeofは式またはキャスト式のいずれかを取る演算子です。このため、私はsizeofにパラテーゼを書く習慣を取りました のみ キャスト式の場合。
char *arr;
struct xxx { ... } v;
私は書きます
sizeof arr
sizeof v
しかし、
sizeof (struct xxx) /* Note the space after the sizeof, it's important */
sizeof (char *)
私は同じことをします return
関数呼び出しではないため、括弧はありません。括弧を付けると、次の式がそれらを必要とするためです。