63

C標準では、さまざまなタイプへのポインターをさまざまなサイズにすることができます。たとえばsizeof(char*) != sizeof(int*)、許可されています。ただし、ポインタをavoid*に変換してから元の型に戻す場合は、元の値と同じであると比較する必要があります。したがって、論理的にはsizeof(void*) >= sizeof(T*)、すべてのタイプTについて正しいですか?

現在使用されている最も一般的なプラットフォーム(x86、PPC、ARM、64ビットバリアントなど)では、すべてのポインターのサイズは、ポイントされたタイプに関係なく、ネイティブレジスタサイズ(4または8バイト)に等しくなります。異なるタイプへのポインターが異なるサイズを持つ可能性がある難解なまたは組み込みのプラットフォームはありますか?私は特にデータポインタについて質問していますが、関数ポインタのサイズが異常なプラットフォームがあるかどうかも知りたいと思います。

私は間違いなくC++のメンバーへのポインターとメンバーへのポインター関数について質問していません。これらは一般的なプラットフォームでは通常とは異なるサイズを取り、クラスへのポインタのプロパティ(非多形、単一継承、多重継承、仮想継承、または不完全型)に応じて、1つのプラットフォーム内で変化することもあります。

4

7 に答える 7

48

C FAQからの回答

Prime 50シリーズは、少なくともPL / Iに対して、セグメント07777、オフセット0をヌルポインターに使用しました。後のモデルでは、セグメント0、オフセット0をCのnullポインターに使用し、TCNP(Test C Null Pointer)などの新しい命令を必要としました。古いワードアドレスのPrimeマシンは、ワードポインタ(int *)よりも大きなバイトポインタ(char *)を必要とすることでも有名でした。

DataGeneralのEclipseMVシリーズには、アーキテクチャでサポートされている3つのポインター形式(ワード、バイト、およびビットポインター)があり、そのうち2つはCコンパイラーによって使用されます。char*およびvoid *のバイトポインターと、その他すべてのワードポインターです。32ビットMVラインが16ビットNovaラインから進化した歴史的な理由から、ワードポインターとバイトポインターには、ワード内のさまざまな場所にオフセット、間接、およびリング保護ビットがありました。不一致のポインタ形式を関数に渡すと、保護違反が発生しました。最終的に、MV Cコンパイラは、ポインタ型の不一致エラーが発生したコードを処理するために、多くの互換性オプションを追加しました。

一部のHoneywell-Bullメインフレームは、(内部)nullポインターにビットパターン06000を使用します。

CDC Cyber​​ 180シリーズには、リング、セグメント、およびオフセットで構成される48ビットのポインターがあります。ほとんどのユーザー(リング11)には、0xB00000000000のnullポインターがあります。古いCDC補数マシンでは、無効なアドレスを含むすべての種類のデータの特別なフラグとしてオール1ビットワードを使用するのが一般的でした。

古いHP3000シリーズは、バイトアドレスとワードアドレスで異なるアドレス指定スキームを使用しています。したがって、上記のいくつかのマシンと同様に、char*およびvoid*ポインターには、他のポインターとは異なる表現が使用されます。

タグ付きアーキテクチャであるSymbolicsLispMachineには、従来の数値ポインタすらありません。ペア(基本的には存在しないハンドル)をCnullポインターとして使用します。

使用している「メモリモデル」に応じて、8086ファミリプロセッサ(PC互換)は16ビットデータポインタと32ビット関数ポインタを使用する場合があります。

一部の64ビットCrayマシンは、単語の下位48ビットでint*を表します。char *はさらに、上位16ビットの一部を使用して、ワード内のバイトアドレスを示します。

追加のリンク:これらのマシンのいくつかについての詳細が記載されたChrisTorekからのメッセージ。

于 2009-10-08T17:07:51.567 に答える
31

あなたが求めているものとはまったく異なりますが、16ビットDOS / Windowsの時代には、ポインタと遠方ポインタを区別していました。後者は32ビットです。

構文が間違っている可能性があります...

int *pInt = malloc(sizeof(int));
int far *fpInt = _fmalloc(sizeof(int));

printf("pInt: %d, fpInt: %d\n", sizeof(pInt), sizeof(fpInt));

出力:

pInt:2、fpInt 4

于 2009-05-27T14:41:37.793 に答える
14

したがって、論理的にはsizeof(void*) >= sizeof(T*)、すべてのタイプTについて、正しいですか?

sizeofはストレージ表現に関するものであり、すべてのビットパターンが有効な値である必要はないため、これは必ずしも従う必要はありません。sizeof(int*) == 8、、が、sizeof(void*) == 4int*の可能な値は2^32以下である適合実装を記述できると思います。なぜあなたがしたいのかわからない。

于 2009-05-27T15:08:46.333 に答える
12

DOS、8088、およびセグメント化されたメモリの黄金時代には、「メモリモデル」を指定するのが一般的でした。たとえば、すべてのコードは64k(1つのセグメント)に収まりますが、データは複数のセグメントにまたがることができます。これは、関数ポインタが2バイト、データポインタが4バイトになることを意味します。誰かがまだその種のマシンのプログラミングをしているのかどうかはわかりませんが、組み込み用途で生き残る人もいるかもしれません。

于 2009-05-27T14:39:17.203 に答える
7

関数ポインタと他のすべてのポインタのサイズが異なるハーバードアーキテクチャマシンを簡単に想像できます。例がわからない...

于 2009-05-27T14:49:50.710 に答える
7

ニアポインタとファーポインタは、ページフラッシュまたはRAMを備えた一部の組み込みマイクロコントローラで引き続き使用され、同じページ(ニアポインタ)または別のページ(ページ情報が含まれているため大きいファーポインタ)のデータを指すことができます。

たとえば、フリースケールのHCS12マイクロコントローラは16ビットのフォンノイマンアーキテクチャを使用しています。つまり、16ビットを超えるアドレスはありません。これにより利用可能なコードスペースの量が制限されるため、8ビットのページレジスタがあります。

したがって、同じコードページ内のデータを指すには、16ビットアドレスを指定するだけです。これはニアポインタです。

別のコードページのデータを指すには、そのページ内に8ビットのページ番号と16ビットのアドレスの両方を含める必要があります。その結果、24ビットのfarポインターが生成されます。

于 2009-05-27T15:51:09.790 に答える
6

たとえば、データへのポインタのサイズが関数へのポインタと異なる可能性があります。これは、組み込みシステムのマイクロプロセッサで発生するのが一般的です。前述のdmckeeのようなハーバードアーキテクチャマシンは、これを簡単に実現します。

gccバックエンドを開発するのが面倒になることがわかりました!:)

編集:私が話している特定のマシンの詳細に入ることができませんが、ハーバードのマシンがこれを簡単に実現できる理由を追加しましょう。ハーバードアーキテクチャには、命令とデータへのさまざまなストレージとパスウェイがあるため、命令のバスがデータのバスよりも「大きい」場合は、データへのポインタよりもサイズが大きい関数ポインタが必要になります。

于 2010-03-10T12:59:57.157 に答える