web-dev-qa-db-ja.com

sizeof(x ++)がxをインクリメントしないのはなぜですか?

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が増加しない理由を誰でも説明できますか?

491
Neigyl R. Noval

C99標準 から(強調は私のものです)

6.5.3.4/2

Sizeof演算子は、そのオペランドのサイズ(バイト単位)を生成します。これは、式または括弧で囲まれた型の名前です。サイズは、オペランドのタイプから決定されます。結果は整数です。オペランドの型が可変長配列型の場合、オペランドが評価されます。そうでない場合、オペランドは評価されず、結果は整数定数になります。

517
pmg

sizeofcompile-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を提供します。

183
codaddict

sizeof(foo)は、コンパイル時に式のサイズを見つけるのに一生懸命努力します。

6.5.3.4:

Sizeof演算子は、そのオペランドのサイズ(バイト単位)を生成します。これは、式または括弧で囲まれた型の名前です。サイズは、オペランドのタイプから決定されます。結果は整数です。オペランドの型が可変長配列型の場合、オペランドが評価されます。そうでない場合、オペランドは評価されず、結果は整数定数になります。

要するに、可変長配列は、実行時に実行されます。 (注: 可変長配列 は特定の機能です。malloc(3)で割り当てられた配列ではありません。)それ以外の場合、type式の計算、およびコンパイル時に。

47
sarnold

sizeofはコンパイル時の組み込み演算子であり、not関数です。これは、括弧なしで使用できる場合に非常に明確になります。

(sizeof x)  //this also works
33
hugomg

注意

この回答は重複からマージされたため、後日が説明されています。

元の

可変長配列sizeofを除き、引数を評価しません。これは、ドラフトC99標準セクション6.5.3.4sizeof 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++] )
20
Shafik Yaghmour

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()、しかしそのようなことは起こりません。

デモ: http://ideone.com/egPMi

sizeofのその他の興味深いプロパティを説明する別のトピックを次に示します。

10
Nawaz

コンパイル中に実行することはできません。したがって、++i/i++は発生しません。また、sizeof(foo())は関数を実行しませんが、正しい型を返します。

10
rakesh

sizeofはコンパイル時に実行されますが、x++は実行時にのみ評価できます。これを解決するために、C++標準では、sizeofのオペランドは評価されません(VLAを除く)。 C標準には次のように書かれています:

[sizeof]のオペランドの型が可変長配列型の場合、オペランドが評価されます。それ以外の場合、オペランドは評価されず、結果は整数定数になります。

0
Edward Karak

sizeof()演算子はデータ型のサイズのみを指定し、内部要素を評価しません。

0
munna