Dev c ++ウィンドウでコンパイルされたコードは次のとおりです。
#include <stdio.h>
int main() {
int x = 5;
printf("%d and ", sizeof(x++)); // note 1
printf("%d\n", x); // note 2
return 0;
}
注1を実行した後、x
は6になるはずです。ただし、出力は次のとおりです。
4 and 5
注1の後にx
が増加しない理由を誰でも説明できますか?
C99標準 から(強調は私のものです)
6.5.3.4/2
Sizeof演算子は、そのオペランドのサイズ(バイト単位)を生成します。これは、式または括弧で囲まれた型の名前です。サイズは、オペランドのタイプから決定されます。結果は整数です。オペランドの型が可変長配列型の場合、オペランドが評価されます。そうでない場合、オペランドは評価されず、結果は整数定数になります。
sizeof
はcompile-time operatorなので、コンパイル時にsizeof
とそのオペランドは結果値に置き換えられます。 オペランドは評価されない(可変長配列の場合を除く)です。結果のtypeのみが重要です。
short func(short x) { // this function never gets called !!
printf("%d", x); // this print never happens
return x;
}
int main() {
printf("%d", sizeof(func(3))); // all that matters to sizeof is the
// return type of the function.
return 0;
}
出力:
2
as short
は私のマシンで2バイトを占有します。
関数の戻り値の型をdouble
に変更:
double func(short x) {
// rest all same
出力として8
を提供します。
sizeof(foo)
は、コンパイル時に式のサイズを見つけるのに一生懸命努力します。
6.5.3.4:
Sizeof演算子は、そのオペランドのサイズ(バイト単位)を生成します。これは、式または括弧で囲まれた型の名前です。サイズは、オペランドのタイプから決定されます。結果は整数です。オペランドの型が可変長配列型の場合、オペランドが評価されます。そうでない場合、オペランドは評価されず、結果は整数定数になります。
要するに、可変長配列は、実行時に実行されます。 (注: 可変長配列 は特定の機能です。malloc(3)
で割り当てられた配列ではありません。)それ以外の場合、type式の計算、およびコンパイル時に。
sizeof
はコンパイル時の組み込み演算子であり、not関数です。これは、括弧なしで使用できる場合に非常に明確になります。
(sizeof x) //this also works
注意
この回答は重複からマージされたため、後日が説明されています。
元の
可変長配列sizeofを除き、引数を評価しません。これは、ドラフトC99標準セクション6.5.3.4
sizeof operator段落2からわかります。
Sizeof演算子は、そのオペランドのサイズ(バイト単位)を生成します。これは、式または括弧で囲まれた型の名前です。サイズは、オペランドのタイプから決定されます。結果は整数です。 オペランドの型が可変長配列型の場合、オペランドが評価されます。そうでない場合、オペランドは評価されず、結果は整数定数になります。
コメント(now removed)は、このようなものが実行時に評価されるかどうかを尋ねました:
sizeof( char[x++] ) ;
そして実際に、このようなものも動作します(両方をライブで見る):
sizeof( char[func()] ) ;
どちらも可変長配列であるためです。とはいえ、どちらにもあまり実用的とは思えません。
可変長配列は、 ドラフトC99標準 セクション6.7.5.2
配列宣言子段落4で説明されています。
[...]サイズが整数定数式で、要素タイプのサイズが既知の定数である場合、配列タイプは可変長配列タイプではありません。 それ以外の場合、配列タイプは可変長配列タイプです。
更新
C11では、VLAの場合の答えが変わります。特定の場合、サイズ式が評価されるかどうかは指定されていません。セクション6.7.6.2
配列宣言子から:
[...]サイズ式がsizeof演算子のオペランドの一部であり、サイズ式の値を変更しても演算子の結果に影響しない場合、サイズ式が評価されるかどうかは指定されていません。
たとえば、次のような場合(ライブで見る):
sizeof( int (*)[x++] )
sizeof
演算子のオペランドは評価されないため、これを行うことができます。
int f(); //no definition, which means we cannot call it
int main(void) {
printf("%d", sizeof(f()) ); //no linker error
return 0;
}
オンラインデモ: http://ideone.com/S8e2Y
つまり、f
のみで使用される場合、関数sizeof
を定義する必要はありません。この手法は、C++でもsizeof
のオペランドが評価されないため、C++テンプレートメタプログラミングで主に使用されます。
なぜこれが機能するのですか? sizeof
演算子はvalueでは動作せず、代わりにtype式の。したがって、sizeof(f())
と記述すると、式f()
のtypeで動作しますが、これは戻り型にすぎません関数f
の。関数が実際に実行された場合に返される値に関係なく、戻り値の型は常に同じです。
C++では、次のこともできます。
struct A
{
A(); //no definition, which means we cannot create instance!
int f(); //no definition, which means we cannot call it
};
int main() {
std::cout << sizeof(A().f())<< std::endl;
return 0;
}
しかし、sizeof
で、A()
を記述して最初にA
のインスタンスを作成し、次にインスタンスでf
を記述して、 A().f()
、しかしそのようなことは起こりません。
sizeof
のその他の興味深いプロパティを説明する別のトピックを次に示します。
コンパイル中に実行することはできません。したがって、++i
/i++
は発生しません。また、sizeof(foo())
は関数を実行しませんが、正しい型を返します。
sizeof
はコンパイル時に実行されますが、x++
は実行時にのみ評価できます。これを解決するために、C++標準では、sizeof
のオペランドは評価されません(VLAを除く)。 C標準には次のように書かれています:
[
sizeof
]のオペランドの型が可変長配列型の場合、オペランドが評価されます。それ以外の場合、オペランドは評価されず、結果は整数定数になります。
sizeof()
演算子はデータ型のサイズのみを指定し、内部要素を評価しません。