コンテンツにスキップ

英文维基 | 中文维基 | 日文维基 | 草榴社区

「Sizeof」の版間の差分

出典: フリー百科事典『ウィキペディア(Wikipedia)』
削除された内容 追加された内容
Cewbot (会話 | 投稿記録)
m Bot作業依頼: sourceタグをsyntaxhighlightタグに置換 (Category:非推奨のsourceタグを使用しているページ) - log
4行目: 4行目:
== 必要性 ==
== 必要性 ==
多くのプログラムで、データ型の大きさがわかると便利な状況がある。最もよくある例としては[[標準Cライブラリ]]の<code>[[malloc]]</code>などによる[[動的メモリ確保]]が挙げられる。組込型の大きさは処理系定義となっており、厳密な大きさは<code>sizeof (char)</code>が<tt>1</tt>であることを除いて標準に定められていない。次の例では10個の要素を持つ<tt>int</tt>型の[[配列]]を格納するのに十分なメモリを確保しようとしている。(処理系に依存したコードを書くつもりでなければ)<tt>int</tt>型の正確な大きさはわからないので<tt>sizeof</tt>が必要となる。
多くのプログラムで、データ型の大きさがわかると便利な状況がある。最もよくある例としては[[標準Cライブラリ]]の<code>[[malloc]]</code>などによる[[動的メモリ確保]]が挙げられる。組込型の大きさは処理系定義となっており、厳密な大きさは<code>sizeof (char)</code>が<tt>1</tt>であることを除いて標準に定められていない。次の例では10個の要素を持つ<tt>int</tt>型の[[配列]]を格納するのに十分なメモリを確保しようとしている。(処理系に依存したコードを書くつもりでなければ)<tt>int</tt>型の正確な大きさはわからないので<tt>sizeof</tt>が必要となる。
<source lang="c">
<syntaxhighlight lang="c">
int *pointer; /*intへのポインタ型、メモリ確保したデータを参照する*/
int *pointer; /*intへのポインタ型、メモリ確保したデータを参照する*/
pointer = malloc(sizeof (int) * 10);
pointer = malloc(sizeof (int) * 10);
</syntaxhighlight>
</source>
このコードで、<tt>malloc</tt>は確保したメモリ領域へのポインタを返すが、その大きさはちょうど<tt>int</tt>型10個分になる。
このコードで、<tt>malloc</tt>は確保したメモリ領域へのポインタを返すが、その大きさはちょうど<tt>int</tt>型10個分になる。


15行目: 15行目:
=== 使用方法 ===
=== 使用方法 ===
<tt>sizeof</tt>演算子は、メモリ上に領域を占めるものであれば、ほとんどどどんなものに対しても使用できる。<tt>sizeof</tt>を使うには、キーワード<code>sizeof</code>の後に変数や[[式 (プログラミング)|式]]あるいは括弧でくくった上で型名を書く。変数や式の場合は、括弧でくくるかどうかは自由である。次の例では<tt>int</tt>型が<tt>char</tt>型の4倍のサイズを持つ実装の場合、<code>1, 4</code>と出力される(なお、<tt>char</tt>型に<tt>sizeof</tt>演算子を適用した結果は全ての実装において1でなければならない)。
<tt>sizeof</tt>演算子は、メモリ上に領域を占めるものであれば、ほとんどどどんなものに対しても使用できる。<tt>sizeof</tt>を使うには、キーワード<code>sizeof</code>の後に変数や[[式 (プログラミング)|式]]あるいは括弧でくくった上で型名を書く。変数や式の場合は、括弧でくくるかどうかは自由である。次の例では<tt>int</tt>型が<tt>char</tt>型の4倍のサイズを持つ実装の場合、<code>1, 4</code>と出力される(なお、<tt>char</tt>型に<tt>sizeof</tt>演算子を適用した結果は全ての実装において1でなければならない)。
<source lang="c">
<syntaxhighlight lang="c">
// C99
// C99
char c;
char c;
printf("%zu, %zu", sizeof c, sizeof (int));
printf("%zu, %zu", sizeof c, sizeof (int));
</syntaxhighlight>
</source>
<source lang="c">
<syntaxhighlight lang="c">
// Microsoft Visual C++
// Microsoft Visual C++
char c;
char c;
printf("%Iu, %Iu", sizeof c, sizeof (int));
printf("%Iu, %Iu", sizeof c, sizeof (int));
</syntaxhighlight>
</source>
<source lang="c">
<syntaxhighlight lang="c">
// キャスト
// キャスト
char c;
char c;
printf("%lu, %lu", (unsigned long) sizeof c, (unsigned long) sizeof (int));
printf("%lu, %lu", (unsigned long) sizeof c, (unsigned long) sizeof (int));
</syntaxhighlight>
</source>
<tt>sizeof</tt>の結果は実装定義の符号無し整数型である<tt>[[size_t]]</tt>型となり、負数になることはない。
<tt>sizeof</tt>の結果は実装定義の符号無し整数型である<tt>[[size_t]]</tt>型となり、負数になることはない。


43行目: 43行目:


次の例では、文字の複写時に[[バッファオーバーラン]]を起こさないよう、<tt>sizeof</tt>を配列の大きさを求めるために用いている。
次の例では、文字の複写時に[[バッファオーバーラン]]を起こさないよう、<tt>sizeof</tt>を配列の大きさを求めるために用いている。
<source lang="c">
<syntaxhighlight lang="c">
/*sizeofを配列に使用する例*/
/*sizeofを配列に使用する例*/
#include <stdio.h>
#include <stdio.h>
60行目: 60行目:
return 0;
return 0;
}
}
</syntaxhighlight>
</source>


[[C99]]で[[可変長配列]]に対して <tt>sizeof</tt>を適用する場合、配列の大きさは実行時に動的に計算され、コンパイル時定数にはならない。
[[C99]]で[[可変長配列]]に対して <tt>sizeof</tt>を適用する場合、配列の大きさは実行時に動的に計算され、コンパイル時定数にはならない。
66行目: 66行目:
==== <tt>sizeof</tt>と不完全型 ====
==== <tt>sizeof</tt>と不完全型 ====
<tt>sizeof</tt>は完全に定義されたデータ型のみに適用できる。配列なら、要素数が変数宣言に含まれていなければならず、構造体や共用体ならメンバが完全に定義されていなければならない。例えば次の二つのソースファイルがあったとする。
<tt>sizeof</tt>は完全に定義されたデータ型のみに適用できる。配列なら、要素数が変数宣言に含まれていなければならず、構造体や共用体ならメンバが完全に定義されていなければならない。例えば次の二つのソースファイルがあったとする。
<source lang="c">
<syntaxhighlight lang="c">
/* file1.c */
/* file1.c */
int arr[10];
int arr[10];
struct x {int one; int two;};
struct x {int one; int two;};
</syntaxhighlight>
</source>


<source lang="c">
<syntaxhighlight lang="c">
/* file2.c */
/* file2.c */
extern int arr[];
extern int arr[];
struct x;
struct x;
</syntaxhighlight>
</source>
どちらのファイルも正しいCのソースであるものの、<tt>file1.c</tt>では<tt>sizeof</tt>を<code>arr</code>と<code>struct x</code>に使用できるが、<tt>file2.c</tt>では完全型でないため使用できない。<tt>file2.c</tt>では<tt>arr</tt>の要素数がわからず、<tt>struct x</tt>のメンバも分からないためである。<tt>file2.c</tt>で<tt>arr</tt>と<tt>struct x</tt>を<tt>sizeof</tt>で使用できるようにするには、<tt>file2.c</tt>の<tt>arr</tt>の宣言に要素数を指定したり、<tt>struct x</tt>の完全な宣言を書いたりする必要がある。
どちらのファイルも正しいCのソースであるものの、<tt>file1.c</tt>では<tt>sizeof</tt>を<code>arr</code>と<code>struct x</code>に使用できるが、<tt>file2.c</tt>では完全型でないため使用できない。<tt>file2.c</tt>では<tt>arr</tt>の要素数がわからず、<tt>struct x</tt>のメンバも分からないためである。<tt>file2.c</tt>で<tt>arr</tt>と<tt>struct x</tt>を<tt>sizeof</tt>で使用できるようにするには、<tt>file2.c</tt>の<tt>arr</tt>の宣言に要素数を指定したり、<tt>struct x</tt>の完全な宣言を書いたりする必要がある。


85行目: 85行目:
<!--{{Main|境界調整}}-->
<!--{{Main|境界調整}}-->
利用者定義型の大きさは[[データ構造アライメント|アライメント]]のためにメンバの大きさの合計よりも大きくなることが規格では許されている。次のコードは多くの環境において<code>8</code>と出力される。
利用者定義型の大きさは[[データ構造アライメント|アライメント]]のためにメンバの大きさの合計よりも大きくなることが規格では許されている。次のコードは多くの環境において<code>8</code>と出力される。
<source lang="c">
<syntaxhighlight lang="c">
struct student {
struct student {
char grade; /* charは1バイト */
char grade; /* charは1バイト */
92行目: 92行目:
printf("%zu", sizeof (struct student));
printf("%zu", sizeof (struct student));
</syntaxhighlight>
</source>
この理由は、多くのコンパイラでは通常[[ワード]]単位にデータを揃えるためであり、個々のメンバも境界を揃えられる。上の場合は、境界調整によってメンバ変数の<code>age</code>が次のワード単位に置かれるのである。このような構造体には境界調整のためにメンバ間やメンバの後ろに「パディング」と呼ばれる余分な隙間が置かれるのである。多くの[[CPU]]ではデータがワード単位のメモリアドレスに置かれていた方が高速に読み書きでき、また中にはワード単位に揃えられていないと読み書きできないCPUもある<ref>Rentzsch, Jonathan. [http://www-128.ibm.com/developerworks/library/pa-dalign/#N100FE "Data alignment: Straighten up and fly right."] www.ibm.com. 08 FEB 2005. Accessed 1 Oct 2006</ref>。
この理由は、多くのコンパイラでは通常[[ワード]]単位にデータを揃えるためであり、個々のメンバも境界を揃えられる。上の場合は、境界調整によってメンバ変数の<code>age</code>が次のワード単位に置かれるのである。このような構造体には境界調整のためにメンバ間やメンバの後ろに「パディング」と呼ばれる余分な隙間が置かれるのである。多くの[[CPU]]ではデータがワード単位のメモリアドレスに置かれていた方が高速に読み書きでき、また中にはワード単位に揃えられていないと読み書きできないCPUもある<ref>Rentzsch, Jonathan. [http://www-128.ibm.com/developerworks/library/pa-dalign/#N100FE "Data alignment: Straighten up and fly right."] www.ibm.com. 08 FEB 2005. Accessed 1 Oct 2006</ref>。


== D ==
== D ==
[[D言語]]では全ての型が持っている[[プロパティ]]として<tt>sizeof</tt>が用意されている。
[[D言語]]では全ての型が持っている[[プロパティ]]として<tt>sizeof</tt>が用意されている。
<source lang="d">
<syntaxhighlight lang="d">
void main()
void main()
{
{
writefln(int.sizeof);
writefln(int.sizeof);
}
}
</syntaxhighlight>
</source>


== .NET ==
== .NET ==

2020年7月5日 (日) 22:51時点における版

主にCC++において、sizeofは、データ型の大きさを求める単項演算子である。sizeofは原則としてコンパイル時計算される演算子で、もしくは括弧でくくった型指定子を与えるとその大きさをバイト単位で返す。これは組込の数値型(整数型浮動小数点数型)、列挙型ポインタ型、利用者定義の複合データ型(構造体共用体、C++のクラス)まで全てのデータ型に対して使用できる。

必要性

多くのプログラムで、データ型の大きさがわかると便利な状況がある。最もよくある例としては標準Cライブラリmallocなどによる動的メモリ確保が挙げられる。組込型の大きさは処理系定義となっており、厳密な大きさはsizeof (char)1であることを除いて標準に定められていない。次の例では10個の要素を持つint型の配列を格納するのに十分なメモリを確保しようとしている。(処理系に依存したコードを書くつもりでなければ)int型の正確な大きさはわからないのでsizeofが必要となる。

int *pointer; /*intへのポインタ型、メモリ確保したデータを参照する*/
pointer = malloc(sizeof (int) * 10);

このコードで、mallocは確保したメモリ領域へのポインタを返すが、その大きさはちょうどint型10個分になる。

一般的に、CとC++で型の大きさを仮定するのは安全でない。標準規格でもchar以外の型がメモリ上で何バイト占めるかを規定していない。たとえば、16ビットシステムでのint型の大きさは通例2バイトであるが、大半の32ビットシステムではint型の大きさは4バイトである。また、構造体や共用体ではアライメントもあり、ますます正確な大きさを求めるのは困難となる。そのようなこともあり、移植性の高いプログラムを書くには型の大きさを求めるためにsizeofを使用することが推奨されている。

CとC++

使用方法

sizeof演算子は、メモリ上に領域を占めるものであれば、ほとんどどどんなものに対しても使用できる。sizeofを使うには、キーワードsizeofの後に変数やあるいは括弧でくくった上で型名を書く。変数や式の場合は、括弧でくくるかどうかは自由である。次の例ではint型がchar型の4倍のサイズを持つ実装の場合、1, 4と出力される(なお、char型にsizeof演算子を適用した結果は全ての実装において1でなければならない)。

// C99
char c;
printf("%zu, %zu", sizeof c, sizeof (int));
// Microsoft Visual C++
char c;
printf("%Iu, %Iu", sizeof c, sizeof (int));
// キャスト
char c;
printf("%lu, %lu", (unsigned long) sizeof c, (unsigned long) sizeof (int));

sizeofの結果は実装定義の符号無し整数型であるsize_t型となり、負数になることはない。

sizeofを関数型、ビットフィールド、不完全型(後述)に対して使用することはできない。

なお、printfなどでsize_t型を書式出力する場合、C99で追加された長さ修飾子zを用いる。 C99に対応していない処理系では、引数をキャストするか、処理系依存の修飾子(たとえばMicrosoft Visual C++ならば修飾子I)を用いる。

もし%uを使用すると、size_t型とunsigned int型のサイズが異なる環境において未定義動作となる。

配列に対するsizeof

sizeof配列型に使用されると、その配列がメモリ上に占める大きさが演算結果となる。配列の大きさは、要素の型の大きさに要素数をかけた値と規定されており、例えばsizeof (T[8])sizeof (T) * 8と同じ値になる。逆に、配列xに対して、sizeof x / sizeof x[0]の演算により、配列の要素数を求めることが可能である。

次の例では、文字の複写時にバッファオーバーランを起こさないよう、sizeofを配列の大きさを求めるために用いている。

/*sizeofを配列に使用する例*/
#include <stdio.h>
#include <string.h>

int main(void)
{
  char buffer[10]; /*要素数10のchar配列*/

  /* 標準入力から読み取った結果をbufferへ9文字までのみ複写する。
   *(sizeof (char)は常に1なので、sizeof buffer[0]で割る必要はない)
   */
  fgets(buffer, sizeof buffer, stdin);

  puts(buffer);
  return 0;
}

C99可変長配列に対して sizeofを適用する場合、配列の大きさは実行時に動的に計算され、コンパイル時定数にはならない。

sizeofと不完全型

sizeofは完全に定義されたデータ型のみに適用できる。配列なら、要素数が変数宣言に含まれていなければならず、構造体や共用体ならメンバが完全に定義されていなければならない。例えば次の二つのソースファイルがあったとする。

/* file1.c */
int arr[10];
struct x {int one; int two;};
/* file2.c */
extern int arr[];
struct x;

どちらのファイルも正しいCのソースであるものの、file1.cではsizeofarrstruct xに使用できるが、file2.cでは完全型でないため使用できない。file2.cではarrの要素数がわからず、struct xのメンバも分からないためである。file2.carrstruct xsizeofで使用できるようにするには、file2.carrの宣言に要素数を指定したり、struct xの完全な宣言を書いたりする必要がある。

実装

コンパイラは言語の実装に適合するように、sizeof演算子をデータ型のメモリ上に占める大きさを結果とするように実装しなければならない。また(既述の例外を除いて)これはコンパイル時計算される演算子であり、アセンブリ言語上では単なる即値になる。

構造体のパディング

利用者定義型の大きさはアライメントのためにメンバの大きさの合計よりも大きくなることが規格では許されている。次のコードは多くの環境において8と出力される。

struct student {
    char grade; /* charは1バイト */
    int age /* intは4バイト */
};
 
printf("%zu", sizeof (struct student));

この理由は、多くのコンパイラでは通常ワード単位にデータを揃えるためであり、個々のメンバも境界を揃えられる。上の場合は、境界調整によってメンバ変数のageが次のワード単位に置かれるのである。このような構造体には境界調整のためにメンバ間やメンバの後ろに「パディング」と呼ばれる余分な隙間が置かれるのである。多くのCPUではデータがワード単位のメモリアドレスに置かれていた方が高速に読み書きでき、また中にはワード単位に揃えられていないと読み書きできないCPUもある[1]

D

D言語では全ての型が持っているプロパティとしてsizeofが用意されている。

void main()
{
    writefln(int.sizeof);
}

.NET

.NET Frameworkでは、Marshal.SizeOfメソッド[2]によってオブジェクトのアンマネージサイズやアンマネージ型のサイズをバイト単位で取得可能である。.NET 4.5.1でジェネリックバージョンのオーバーロードが追加された。そのほか、各.NET言語に類似の組み込み言語機能が用意されていることがあるが、System.Booleanに対する演算結果など、必ずしもMarshal.SizeOfと同じ結果になるとは限らない。

C++/CLI

C++/CLIsizeof演算子はネイティブ型(基本型およびポインタ型)に用いる限りコンパイル時定数となり、基本的にC++と同じである。しかし値クラス(value class)型、(マネージ)ハンドル型やジェネリック型引数に対して用いられたときにはコンパイル時定数でなくなる。また参照クラス (ref class) 型やインターフェイス型に対して用いることはできない(不正となる)[3]

C#

C#sizeof演算子は、アンマネージ型(組み込み型、列挙型、ポインタ型、参照型のフィールドやプロパティを含まないユーザー定義の構造体)のサイズをバイト単位で取得する。結果はint型となる。特定の組み込み型に対してsizeof演算子を用いた場合の結果はコンパイル時定数となるが、それ以外の型に使用した場合はコンパイル時定数とならない。また、sizeof演算子を使用するにはunsafeモードが必要だが、C# 2.0以降は組み込み型に対するsizeofに関してのみunsafeが不要となった[4]

Visual Basic

Visual Basicでは、Len関数などが存在する。Lenは文字列を引数に与えると文字列の長さを返すが、その他の型の変数を与えると変数の大きさを返す。

ActiveBasic

ActiveBasicでは、Visual Basicと同様のLen組込関数を持っているほか、SizeOf組込関数を持っている。Lenは型名を指定することができないが、SizeOfは型名を指定できる。逆にSizeOfに変数や式を指定することはできない。

脚注