• ベストアンサー

ポインタのサイズ

ポインタのサイズは、 int型のポインタでも、char型のポインタでも、 doubleのポインタでも、構造体のポインタでも、 全部サイズは4バイトです。 というのを見かけましたが、ほんとうですか? 教えてください。

質問者が選んだベストアンサー

  • ベストアンサー
  • bnosuke-x
  • ベストアンサー率39% (43/110)
回答No.7

PIC等のマイクロコンピュータでは、メモリモデルにより違いますが、16ビットと24ビットがポインタのサイズでした。 (参考URLをご覧下さい) 「C言語では」と聞かれると、処理系(CPU,アーキテクチャ,コンパイラ,OS)に依ってマチマチになりますし、 「これこれの処理系」と聞かれれば、こうです、と定まった答えが出ます。 C言語は高級言語の皮をかぶったアセンブラみたいなものですから、不親切に思える「なぜ、なに」がたくさん出てきます。 Cの言語仕様とライブラリAPIを超えた範囲にも目を向けて勉強していただきたいと思います。 (特にCPUとメモリ、スタックの使われ方など)

参考URL:
http://ww1.microchip.com/downloads/en/DeviceDoc/51288C_JP.pdf
noname#168725
質問者

お礼

回答どうもありがとうございます! 詳しい解説ありがとうありがとうございます。 自分には難しそうですが、参考になります! ありがとうございます!

全文を見る
すると、全ての回答が全文表示されます。

その他の回答 (10)

  • MrBan
  • ベストアンサー率53% (331/615)
回答No.11

失礼。longだとLONG_MINには拘束されますね。 (ISO/IEC14882 $18.2.2, ISO/IEC9899 $5.4.2.1あたり) # 蛇足:intptr_t等の定義はC99以降、現状では処理系を選びます。 # (とはいえstdint.hくらいなら仕様片手に自作できるでしょうが)

全文を見る
すると、全ての回答が全文表示されます。
  • Tacosan
  • ベストアンサー率23% (3656/15482)
回答No.10

確かに個々の型の大きさは処理系定義ですが, 最低の大きさが規格にあります. で, long は最低 32bit なので「long が 24bit」はアウトです>#9 あと, 「どうしてもポインタの値を整数型の変数に入れたい」というときには intptr_t または uintptr_t を使うのがベスト.

全文を見る
すると、全ての回答が全文表示されます。
  • MrBan
  • ベストアンサー率53% (331/615)
回答No.9

> この型名は規格上は OK なんでしょうか? これがもしも「shortが24bit」または「longが24bit」なら処理系定義なのでOKですが、 「short long」という型名は言語仕様的には違反ですね。 「標準の型を提供。さらに、独自の型を提供」という説明ですし、 処理系の独自拡張ということになると思います。一般性はありません。

全文を見る
すると、全ての回答が全文表示されます。
  • noocyte
  • ベストアンサー率58% (171/291)
回答No.8

#7 さんの参考 URLを見ると,short long 型 (24ビット) なんてのがあるんですね! (11ページ) この型名は規格上は OK なんでしょうか?

全文を見る
すると、全ての回答が全文表示されます。
  • t_nojiri
  • ベストアンサー率28% (595/2071)
回答No.6

皆さん書かれてる通り、OS、コンパイラ、実記環境(32bit、64bit)等に左右されます。 とはいえ、32ビット環境に限った話をすると質問条件に合うポインタは4バイトとなるケースが多いとは言えます。 但し、こういう定義されてない物は必ずsizeof()等でサイズ取得した方がコードの汎用性高くなります。(グレー扱いするのが常套手段です。)

noname#168725
質問者

お礼

すばやい回答ありがとうございます! 的確なご指摘参考になりました!

全文を見る
すると、全ての回答が全文表示されます。
  • MrBan
  • ベストアンサー率53% (331/615)
回答No.5

常に同じである保証がないのは、既に書かれている通りです。 言語仕様上のサイズ保証はありませんし、クラスメンバのポインタが別サイズとかもありえます。 ポインタと整数のマッピングはimplementation-definedなので、 基本的には処理系(通常はコンパイラ)が決定します。 そのCPU上でもっとも効率的なサイズを使うのが普通ですが、 例えばvoid*へのキャスト時などにコンパイラが変換コードを 生成するなどの手段もないとはいえません。 # Win32等しか使ってないと、大抵4なので常に4だと思っちゃう人もいますし、 # 全てのポインタサイズを4にしてるコンパイラもあるので、 # 見かけた情報は何らかの条件が付いていたのかもしれません。

noname#168725
質問者

お礼

すばやい回答ありがとうございます! いろいろ詳しい回答ありがとうございます!

全文を見る
すると、全ての回答が全文表示されます。
  • sakusaker7
  • ベストアンサー率62% (800/1280)
回答No.4

この説明がなされる前に、なにか限定条件がついていませんでしたか? すでにいくつか例も挙がっていますが、ほかにも char * と その他のポインタ型でサイズの違う環境がありました (多分現役ではないので過去形)。 ですから、いついかなる場合でもなりたつというものではありません。 また、64bit CPUが使われている環境の場合、int は 64bitではなく 32bitのままというものもありますので(たとえばWindowsがそう)、 int のサイズがポインタのサイズと常に等しいということもありません。

noname#168725
質問者

お礼

すばやい回答ありがとうございます! いろいろ情報ありがとうございます!

全文を見る
すると、全ての回答が全文表示されます。
  • noocyte
  • ベストアンサー率58% (171/291)
回答No.3

プログラム用のメモリとデータ用のメモリが分かれているプロセッサでは, データ (int,char,double 等) へのポインタと,プログラム (関数) への ポインタのサイズが異なる場合があります. 16ビット時代の x86 はプログラム用とデータ用のメモリのサイズがそれぞれ, ・64KB 未満 (ポインタは2バイト) ・64KB 以上 (ポインタは4バイト) の2つの場合があり,4通りの組合せ (それぞれをメモリ・モデルと呼んでいた) が ありました.どのメモリ・モデルを使用するかは,プログラムのサイズと扱うデータ量 に応じて決定していました. 現在でも,DSP (デジタルシグナルプロセッサ) のようにプログラムメモリと データメモリが分かれているプロセッサではそうなっている可能性があります. (DSP を使ったことがないのでわかりませんが.) デジタルシグナルプロセッサ (Wikipedia) http://ja.wikipedia.org/wiki/%E3%83%87%E3%82%B8%E3%82%BF%E3%83%AB%E3%82%B7%E3%82%B0%E3%83%8A%E3%83%AB%E3%83%97%E3%83%AD%E3%82%BB%E3%83%83%E3%82%B5

noname#168725
質問者

お礼

すばやい回答ありがとうございます! いろいろ参考になりました! ありがとうございます!

全文を見る
すると、全ての回答が全文表示されます。
  • tatsu99
  • ベストアンサー率52% (391/751)
回答No.2

>というのを見かけましたが、ほんとうですか? 本当です。 正確に言えば、それは32ビットモードの話で、 64ビットモードのコンパイラではすべて8バイトになります。 ポインターは、アドレスを示すもので、そのアドレスの示す先に、 charがあろうが、intがあろうが、なにがあってもアドレスを示すサイズは 変わりません。その為に、全て4バイトになります。

noname#168725
質問者

お礼

すばやい回答ありがとうございます! 何となくつかめました! ありがとうございます!

全文を見る
すると、全ての回答が全文表示されます。
  • snow765
  • ベストアンサー率26% (8/30)
回答No.1

CPUとかコンパイラとかによっていろいろです。 基本的にはINT型といっしょかな?

noname#168725
質問者

お礼

すばやい回答ありがとうございます! 参考にします!

全文を見る
すると、全ての回答が全文表示されます。

関連するQ&A

  • 変数 および ポインタのサイズ(バイト数)について

    sizeof演算子を使ってchar int float double型のバイト数を調べると、char 型については1バイトと決まっていて、int float doubleについては2から8バイト(処理系によって違う)なのは理解できます。しかし、char* int* float* double*型(ポインタ型)のバイト数は2から4バイトになるのが多いとおもいますが、どういう理由でポインタ型のバイト数が決まるのか、その理由をお教え願いたく思います。16ビットcpuあるいは32ビットcpuと言うハードの影響なのかそれとも何かソフトによるのか、その理由を知りたいと思います。なお私の処理系ではポインタは全て4バイトになっています。特に不思議に思うのはchar型は1バイトなのに、char*型が4バイトになっていることです。 宜しく願います。

  • 構造体へのポインタについて

    初心者です。 C入門書の著者のサポートページには正誤表とダウンロードしかないためこちらで質問させていただきます。 下記のコードの下から二行目の構造体へのポインタ (Car *) について、中学生に説明するように基本的な考え方、目的、書式、参考URLなどを教えて下さい。 ポインタについては、該当の章を読み直し基本事項については理解しておりますが、突然あるページから(Void *)や(Char *)など括弧で閉じるものが説明なしに出てきてちょっと混乱してます。(汗 どうぞ宜しくお願い致します。 #include<stdio.h> /* 構造体型struct Carの宣言 */ typedef struct Car{ int num; double gas; }Car; int main(void) { printf("int型のサイズは%dバイトです。¥n", sizeof(int)); printf("double型サイズは%dバイトです。¥n", sizeof(double)); printf("構造体structCar型のサイズは%dバイトです。¥n", sizeof(Car)); printf("構造体struct Car型へのポインタのサイズは%dバイトです。¥n", sizeof(Car *)); return 0; }

  • C言語 ダブルポインタを引数にもつAPI

    GetBuf ( char ** address, size_t *dataSize ); 第1引数: バッファの先頭アドレスをかえす 第2引数: バッファサイズをByte単位で返す 戻り値 1:成功      -1 取得失敗 typedef struct Test_t{ char* tempAddr; /* 先頭アドレスを格納 */ int bufSize; /* サイズを格納 */ } test_t 上記のAPIから情報を取得し、以下の構造体にデータを保持しようとしていますが GetBuffのダブルポインタの情報を構造体のメンバtempAddrに格納するにはどうしたらよいでしょうか このAPIのように引数でダブルポインタを使用するケースは一般的なのでしょうか? 教えていただけるとうれしいです。 よろしくお願い致します。

  • void型へのポインタ

    というのがC言語にありますよね? このvoid型へのポインタというのは、 どのようにイメージすればいいのでしょうか? 例えばchar型へのポインタなら、 指している領域は 1バイトの領域ですよね? ではvoid型は? また malloc関数を 使って char *p; p=(char *)malloc(1000); とするとでchar型にキャストしているから、 1個1バイト分の領域が1000個用意して、 先頭アドレスをpに格納するのですよね? では、 int *q; q=(int *)malloc(1000); としたら、用意されるのは、int型にキャストしているから 1個2バイト分の領域が500個用意されるのでしょうか? お願いします。

  • 構造体の初期化の時にポインタを入れるにはどうしたらいいですか?

    構造体の初期化の時にポインタを入れるにはどうしたらいいですか? 例えば、このような構造体で↓ struct PACKET { uint16_t size; // データの長さ uint16_t *data; // データバイト列 }; 初期化の時にsizeとdataを入れるにはどうしたらいいのでしょうか? dataがuint16_t*じゃなくてchar*なら struct PACKET { uint16_t size; // データの長さ char *data; // データバイト列 }; struct PACKET p = { 5, "12345" }; というようにできるのですが・・・

  • ポインタのサイズ

    ポインタのサイズがintと同じになるのは知っているのですが、 以下のコードの場合、 typedef struct hoge{ char buf1[8]; char buf2[16]; }HOGE; void test_func(HOGE *pHoge) { printf("型[%d],実際[%d]\r\n", sizeof(HOGE), sizeof(*pHoge)); memset(pHoge, 0x00, sizeof(*pHoge)); } 正しくサイズが取得できるのですが、 この使い方はC99の仕様的には正しいのでしょうか? よろしくお願いします。

  • int型ポインタの加算

    void foo() {   int *ptrInt=0;   char *ptrChar=0;   ptrInt++;   ptrChar++; } Windows2000上で、上記を実行すると ptrIntは4になります。 ptrCharは1になります。 なぜでしょうか。 32ビットとはいえ、 ptrIntとptrCharはアドレスを示しますよね。 アドレスに1加算するのだから、 int型、char型に関係なく、 いずれも1になるべきだと思います。 int型のポインタの場合示すデータは4バイトなので、 ポインタ1加算は、4(バイト)加算になるということでしょうか。

  • ポインタの引数について。

    C言語初心者です。 既存のプログラムを直そうとしているのですが、ポインタの概念がいまいち理解できていないのか、修正した箇所がうまく動きません。 どうすればよいかをご教示いただけませんでしょうか。 元のプログラムは void sub() { SOCKET s; struct msg r_msg; int time; int cc; cc = sub_recv(s, &r_msg, time); ・・・ } void sub_recv(s,*msg,time) { unsigned char *pack; int cc; int len; pack = (unsigend char *)msg cc = recv(s, (char *)pack, len, 0); if(cc < 0) return(cc); ・・・ } という感じでr_msg構造体にrecvで受け取ったものを入れて行きます。 ccにはrecv()の戻り値でサイズが返ってきて直後のifにはひっかかりません。 構造体の中でサイズが固定されているため、可変にするために以下のようにしたいです。 extern int buflen; void sub() { SOCKET s; unsigned char *r_msg; int time; int cc; r_msg=(char *)malloc(sizeof(char)*buflen ); cc = sub_recv(s, r_msg, time); free(r_msg); ・・・ } void sub_recv(s,*msg,time) { unsigned char *pack; int cc; int len; pack = (unsigend char *)msg /*ここの代入は無意味と思いますがなくしても同様の結果のなので残してます。*/ cc = recv(s, (char *)pack, len, 0); if(cc < 0) return(cc); ・・・ } しかし、このような修正で*r_msgにはrecv()で受け取った内容が入る気がするのですが、 ccには-1が入ってしまい、ifに引っかかって終了してしまいます。 この時のerrnoを見ても104が入り、connection reset by peerといった感じです。 recv()の第二引数にはこれがバッファが用意されてればいいと解釈しておりますが、 これではバッファが1バイトしかとれていないなどあるのでしょうか。 因に、send()がないからというのはありません。 キャストが間違えているなどもあるかもしれませんが、宜しくお願いします。

  • ポインタ

    #include "stdafx.h" #include <ctype.h> #include <string.h> #include <stdlib.h> typedef struct { char number[6]; char class_type[20]; char name[8]; char subject[5]; } my; my data[100]; int main(int argc, char* argv[]) { FILE *fp; int field = 0, line = 0; char buf[1000], *str; char bufG[1111]; int i; if((fp=fopen("test.txt","r"))==NULL){ printf("ファイルが開けません"); } while(fgets(buf,1000,fp) !=NULL){ str=buf; while(*str != '\0'){ if(*str != ','){ for(i = 0; *str != ',' && *str != '\0' ; i++){ if(*str == '\n'){ } else{ bufG[i] = *str; } str++; } bufG[i] = '\0'; // printf("%s", bufG); switch(field){ case 0: strcpy(data[line].number, bufG); break; case 1: strcpy(data[line].class_type, bufG); break; case 2: strcpy(data[line].name, bufG); break; case 3: strcpy(data[line].subject, bufG); break; } field++; } else{ str++; } } line++; field = 0; } printf("%s", data[2].subject); fclose(fp); return 0; } このプログラムをベースにしてメモリの無駄を省けるような プログラムに修正したいのですが、 ポインタほんとできなくて困ってます。 教えていただいてメモリを取る位置とかは大体わかりました。 まず構造体のメモリをとります。しかしこのままでは固定長になってるので 構造体を少しいじくりますよね。 構造体の中身なのですが typedef struct{ int number; char *class_type; char *name; char *subject; } my; my *data; にして data = malloc(100); このような形でとります。 文字列の型ですがchar *class_typeのようにポインタで宣言しないと bufGを代入して値を入れるときに型が合いませんので 配列にしないのであればポインタ型宣言でいいと思います。 しかしポインタで宣言してstrcpy(・・)の所を data[line].class_type = bufG にするとエラーはでませんが*strの値が変わる度に data[line].class_typeの値が変動するのでdata[line].class_typeが 国語 とかになったりします。 なんかもうさっぱりわからないんですが どうすればいいのでしょうか? 変換したソースがほしいです。

  • void型ポインタについて

    -------------------------------- #include<stdio.h> void uni_disp(void *p,int typ); int main() { int idt=123456; double ddt=56.789; char ss[]="abcdef"; uni_disp(&idt,'I'); uni_disp(&ddt,'D'); uni_disp(ss,'S'); uni_disp("STRING",'S'); return 0; } void uni_disp(void *p,int typ) { if(typ=='I'){ printf("%d\n",*(int *)p); } else if(typ=='D'){ printf("%f\n",*(double *)p); } else if(typ=='S'){ printf("%s\n",(char *)p); } } ----------------------------------- 以上のプログラム等で、void型ポインタをint型ポインタ、double型ポインタとみなす場合の、「*(int *)p」や「*(double *)p」の表記がどういう仕組みになっているか分かりません。 「*(int)p」などはエラーが出るのですが、やはり表記の意味を理解していないため何故か分かりません。 「*(int *)p」などの表記を分解して教えていただけると嬉しいです。