ポインタと同じサイズの整数型はありますか? すべてのマイクロアーキテクチャで保証されていますか?
10 に答える
このウィキペディアのページによると、C99 では、stdint.h ヘッダーでintptr_t と uintptr_t を宣言する場合がありますが、もちろん必要です
- C99
- 標準のこのオプション部分を実装することを選択したコンパイラ実装者
ですから、一般的に、これは難しいと思います。
簡単に言えば、いいえ。すべてのアーキテクチャで保証されているわけではありません。
私の質問は:なぜですか?a を格納するのに十分な大きさの型を割り当てたい場合、割り当てるのにvoid*
最適なのは (驚くべきことに:-) avoid*
です。に収まる必要があるのはなぜint
ですか?
編集:重複した質問へのコメントに基づいて、追加情報を示すためにポインター (1,2,3) の特別な値を保存する必要があります。
いいえ!!これをしないでください!. 1、2、および 3 が完全に有効なポインターではないという保証はありません。ポインタを 4 バイト境界に揃える必要があるシステムでは、これが当てはまるかもしれませんが、すべてのアーキテクチャについて質問されたので、高い価値として移植性があると思います。
正しい別の方法を見つけてください。たとえば、共用体を使用します (メモリからの構文、間違っている可能性があります)。
typedef struct {
int isPointer;
union {
int intVal;
void *ptrVal;
}
} myType;
次に、isPointer 'boolean' を使用して、共用体を整数またはポインターとして扱うかどうかを決定できます。
編集:
実行速度が最も重要な場合は、typedef ソリューションが適しています。基本的に、実行したいプラットフォームごとに必要な整数を定義する必要があります。条件付きコンパイルでこれを行うことができます。また、ランタイム チェックを追加して、各プラットフォーム用に正しくコンパイルされていることを確認します (ソースで定義していますが、" cc -DPTRINT_INT
" のようにコンパイラ フラグとして渡します)。
#include <stdio.h>
#define PTRINT_SHORT
#ifdef PTRINT_SHORT
typedef short ptrint;
#endif
#ifdef PTRINT_INT
typedef int ptrint;
#endif
#ifdef PTRINT_LONG
typedef long ptrint;
#endif
#ifdef PTRINT_LONGLONG
typedef long long ptrint;
#endif
int main(void) {
if (sizeof(ptrint) != sizeof(void*)) {
printf ("ERROR: ptrint doesn't match void* for this platform.\n");
printf (" sizeof(void* ) = %d\n", sizeof(void*));
printf (" sizeof(ptrint ) = %d\n", sizeof(ptrint));
printf (" =================\n");
printf (" sizeof(void* ) = %d\n", sizeof(void*));
printf (" sizeof(short ) = %d\n", sizeof(short));
printf (" sizeof(int ) = %d\n", sizeof(int));
printf (" sizeof(long ) = %d\n", sizeof(long));
printf (" sizeof(long long) = %d\n", sizeof(long long));
return 1;
}
/* rest of your code here */
return 0;
}
私のシステム (Ubuntu 8.04、32 ビット) では、次のようになります。
ERROR: ptrint typedef doesn't match void* for this platform.
sizeof(void* ) = 4
sizeof(ptrint ) = 2
=================
sizeof(short ) = 2
sizeof(int ) = 4
sizeof(long ) = 4
sizeof(long long) = 8
その場合、PTRINT_INT (または long) でコンパイルする必要があることがわかります。#if を使ってコンパイル時にこれをキャッチする方法があるかもしれませんが、今のところ調査する気にはなれませんでした。ポインタを保持するのに十分な整数型がないプラットフォームに遭遇した場合、運が悪いです。
特殊なポインター値 (1、2、3) を使用して整数を表すことも、すべてのプラットフォームで機能するとは限らないことに注意してください。これは、実際にはポインターの有効なメモリ アドレスである可能性があります。
それでも、あなたが私のアドバイスを無視するつもりなら、あなたを止めるために私にできることはあまりありません. 結局のところ、それはあなたのコードです:-)。1 つの可能性は、malloc からのすべての戻り値をチェックし、1、2、または 3 を取得した場合は、malloc を再度実行することです (つまり、これを自動的に行う mymalloc() を使用します)。これはマイナーなメモリ リークになりますが、特殊なポインターと実際のポインターの間で衝突が発生しないことが保証されます。
C99 標準では、標準の int 型が定義されています。
7.18.1.4 オブジェクト ポインターを保持できる整数型 次の型は、void への有効なポインターをこの型に変換し、その後 void へのポインターに戻すことができるというプロパティを持つ符号付き整数型を指定します。元のポインター:
intptr_t
次の型は、void への任意の有効なポインターをこの型に変換し、その後 void へのポインターに戻すことができるプロパティを持つ符号なし整数型を指定します。結果は元のポインターと等しくなります。
uintptr_t
これらのタイプはオプションです。
C99 では、size_t と ptrdiff_t も定義されています。
タイプは
ptrdiff_t
これは、2 つのポインターを減算した結果の符号付き整数型です。
size_t
sizeof 演算子の結果の符号なし整数型です。と
私が見たアーキテクチャでは、オブジェクトの最大サイズはメモリ全体に等しいため、sizeof(size_t) == sizeof(void*) ですが、C89 に両方とも移植できるものを認識していません (これsize_t
は です) 。十分な大きさであることが保証されています(これuintptr_t
はです)。
これは標準の 32 ビット システムでは当てはまりますが、確かに保証はなく、当てはまらない多くのアーキテクチャを見つけることができます。たとえば、よくある誤解は、x86_64 の sizeof(int) が 8 になるというものです (これは 64 ビット システムであるためだと思います) が、そうではありません。x86_64 では、sizeof(int) は 4 のままですが、sizeof(void*) は 8 です。
この問題の標準的な解決策は、すべての int 型 (short int、int、long int) のサイズをチェックし、それらを void* と比較する小さなプログラムを作成することです。一致する場合は、intptr 型を定義するコードを出力します。これをヘッダー ファイルに入れて、新しい型を使用できます。
このコードをビルド プロセスに含めるのは簡単です (make
たとえば、 を使用)。
いいえ、移植可能なポインター対応の整数型に最も近いのはintptr_t
andptrdiff_t
です。
通常、sizeof(*void) はメモリ バス幅に依存し (必ずしもそうとは限りません - RISC AS/400 以前のアドレス バスは 48 ビットでしたが、ポインターは 64 ビットでした)、int は通常、CPU の汎用レジスタと同じ大きさです (また例外 - SGI C は 64 ビット MIPS で 32 ビット int を使用していました)。
したがって、保証はありません。
いいえ。
C標準が標準のintサイズを指定しているとは思いません。それをそこにあるすべてのアーキテクチャ(8/16/32/64ビットなど)と組み合わせると、何も保証する方法がありません.
int データ型は、ほとんどのアーキテクチャでの答えです。
ただし、すべての(マイクロ) アーキテクチャについて、これが保証されるわけではありません。
答えは「いいえ」のようですが、必要なのは両方として機能できる型だけである場合は、共用体を使用できます。
union int_ptr_t {
int i;
void* p;
};