例:sizeof(char*)
は4を返します。int*
、long long*
など、私が試したすべてのものを返します。これに例外はありますか?
保証は、sizeof(char) == 1
です。 sizeof(int *) == sizeof(double *)
の保証を含め、他の保証はありません。
実際には、ポインターは16ビットシステムではサイズ2(ある場合)、32ビットシステムでは4、64ビットシステムでは8になりますが、特定のコンポーネントに依存しても何も得られませんサイズ。
単純なx86 32ビットプラットフォームでも、さまざまなポインターサイズを取得できます。例として、これを試してください。
struct A {};
struct B : virtual public A {};
struct C {};
struct D : public A, public C {};
int main()
{
cout << "A:" << sizeof(void (A::*)()) << endl;
cout << "B:" << sizeof(void (B::*)()) << endl;
cout << "D:" << sizeof(void (D::*)()) << endl;
}
Visual C++ 2008では、メンバー関数へのポインターのサイズが4、12、および8になります。
レイモンド・チェンはこれについて話しました ここ 。
既に投稿されたリストの別の例外。 32ビットプラットフォームでは、ポインターは6、4ではない、バイトを使用できます。
#include <stdio.h>
#include <stdlib.h>
int main() {
char far* ptr; // note that this is a far pointer
printf( "%d\n", sizeof( ptr));
return EXIT_SUCCESS;
}
Open Watcomでこのプログラムをコンパイルして実行すると、サポートされるfarポインターは32ビットオフセットと16ビットセグメント値で構成されるため、6を取得します。
64ビットマシン用にコンパイルしている場合、8になります。
技術的に言えば、C標準はsizeof(char)== 1のみを保証し、残りは実装次第です。しかし、最新のx86アーキテクチャ(Intel/AMDチップなど)では、かなり予測可能です。
おそらく16ビット、32ビット、64ビットなどと説明されているプロセッサを聞いたことがあるでしょう。これは通常、プロセッサが整数にNビットを使用することを意味します。ポインタはメモリアドレスを格納し、メモリアドレスは整数であるため、これにより、ポインタに使用されるビット数が効果的にわかります。 sizeofは通常バイト単位で測定されるため、32ビットプロセッサー用にコンパイルされたコードはポインターのサイズを4(32ビット/ 8バイト/バイト)として報告し、64ビットプロセッサーのコードはポインターのサイズを8として報告します(64ビット/ 1バイトあたり8ビット)。これは、32ビットプロセッサのRAMの4GBの制限が原因です。各メモリアドレスがバイトに対応する場合、より多くのメモリをアドレスするには、32ビットより大きい整数が必要です。
16/32/64ビットの違いに加えて、さらに奇妙なことが起こります。
Sizeof(int *)が1つの値、おそらく4であるが、sizeof(char *)が大きいマシンがありました。バイトではなく自然にワードをアドレス指定するマシンは、C/C++標準を適切に実装するために、本当に必要なWordの部分を指定するために、文字ポインターを「拡張」する必要があります。
ハードウェア設計者はバイトアドレス指定の価値を知っているため、これは現在非常に珍しいことです。
ポインタのサイズは、基本的に、それが実装されているシステムのアーキテクチャに依存します。たとえば、32ビットのポインターのサイズは、64ビットマシンでは4バイト(32ビット)および8バイト(64ビット)です。マシンのビットタイプは、メモリアドレスにすぎません。 32ビットマシンは2^32
アドレススペースを持つことができ、64ビットマシンは2^64
アドレススペースを持つことができます。したがって、ポインター(メモリー位置を指す変数)は、マシンが保持するメモリーアドレス(2^32 for 32 bit and 2^64 for 64 bit
)のいずれかを指すことができるはずです。
このため、ポインターのサイズは32ビットマシンでは4バイト、64ビットマシンでは8バイトであることがわかります。
8ビットおよび16ビットのポインターは、ほとんどのロープロファイルマイクロコントローラーで使用されます。それは、すべての洗濯機、マイクロ、冷蔵庫、古いテレビ、さらには車を意味します。
これらは、実際のプログラミングとは何の関係もないと言えます。しかし、ここに1つの実例があります。2バイトポインターを備えた1-2-4k RAM(チップに依存)を備えたArduino.
それは最近、安価で、誰でもアクセスでき、コーディングする価値があります。
64ビット(または何でも)システムについて人々が言ったことに加えて、オブジェクトへのポインター以外の種類のポインターがあります。
メンバーへのポインターは、コンパイラーによる実装方法に応じて、ほぼ任意のサイズになる場合があります。必ずしもすべてが同じサイズであるとは限りません。 PODクラスのメンバーへのポインターを試してから、複数の基底を持つクラスの基底クラスの1つから継承されたメンバーへのポインターを試してください。なんて楽しい。
私が思い出すところから、それはメモリアドレスのサイズに基づいています。したがって、32ビットアドレススキームのシステムでは、sizeofは4バイトを返すため、4を返します。
一般に、異なるプラットフォームでコンパイルすると、sizeof(ほとんど何でも)が変更されます。 32ビットプラットフォームでは、ポインターは常に同じサイズです。他のプラットフォーム(明らかな例は64ビット)では、これは変更される可能性があります。
いいえ、ポインタのサイズはアーキテクチャによって異なる場合があります。多数の例外があります。
ポインターとintのサイズは、Windows 32ビットマシンのTurbo Cコンパイラーでは2バイトです。
したがって、ポインターのサイズはコンパイラー固有です。ただし、一般的にほとんどのコンパイラは、32ビットの4バイトポインター変数と64ビットマシンの8バイトポインター変数をサポートするように実装されています)。
そのため、ポインターのサイズはすべてのマシンで同じではありません。
Win64(Cygwin GCC 5.4)では、以下の例を見てみましょう:
まず、次の構造体をテストします。
struct list_node{
int a;
list_node* prev;
list_node* next;
};
struct test_struc{
char a, b;
};
テストコードは次のとおりです。
std::cout<<"sizeof(int): "<<sizeof(int)<<std::endl;
std::cout<<"sizeof(int*): "<<sizeof(int*)<<std::endl;
std::cout<<std::endl;
std::cout<<"sizeof(double): "<<sizeof(double)<<std::endl;
std::cout<<"sizeof(double*): "<<sizeof(double*)<<std::endl;
std::cout<<std::endl;
std::cout<<"sizeof(list_node): "<<sizeof(list_node)<<std::endl;
std::cout<<"sizeof(list_node*): "<<sizeof(list_node*)<<std::endl;
std::cout<<std::endl;
std::cout<<"sizeof(test_struc): "<<sizeof(test_struc)<<std::endl;
std::cout<<"sizeof(test_struc*): "<<sizeof(test_struc*)<<std::endl;
出力は次のとおりです。
sizeof(int): 4
sizeof(int*): 8
sizeof(double): 8
sizeof(double*): 8
sizeof(list_node): 24
sizeof(list_node*): 8
sizeof(test_struc): 2
sizeof(test_struc*): 8
64ビットでは、sizeof(pointer)
は8
であることがわかります。
ポインタのサイズが4バイトである理由は、32ビットアーキテクチャ用にコンパイルしているためです。 FryGuyが指摘したように、64ビットアーキテクチャでは8が表示されます。
ポインターはアドレスの単なるコンテナーです。 32ビットマシンでは、アドレス範囲は32ビットであるため、ポインターは常に4バイトになります。 64ビットマシンでは、アドレス範囲が64ビットの場合、ポインターは8バイトになります。
完全性と歴史的関心のために、64ビットの世界では、主にUnixタイプのシステムとWindowsの間で、LLP64およびLP64という名前のlongおよびlong longタイプのサイズに関する異なるプラットフォーム規則がありました。 ILP64という名前の古い標準も、int = 64ビット幅になりました。
Microsoftは、longlong = 64ビット幅のLLP64を維持しましたが、移植を容易にするためにlongは32のままでした。
Type ILP64 LP64 LLP64
char 8 8 8
short 16 16 16
int 64 32 32
long 64 64 32
long long 64 64 64
pointer 64 64 64