• ベストアンサー

ポインタの演算について

ポインタの演算に関して質問させて下さい。 unsigned long型のポインタに+1すると実際のアドレスは+4になってしまいます。 ex) unsigned long *a: 0xb7de1000 a+1 : 0xb7de1004 よって、アドレス+1(上では0xb7de1001)に値をかきこみたいのですが、 *(a+1)=ffffffffとすると 0xb7de1004に値が書きこまれてしまいます。 32bitの値を書きこみたいので現在は char *a: *(unsigned long*)(a+1)=ffffffff としているのですが、キャストを使わずに同様のことを実現することは可能でしょうか? ご教授よろしくお願いします。

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

  • ベストアンサー
  • YOKO-bee
  • ベストアンサー率50% (2/4)
回答No.4

前提が気になるところですが・・・ (1)unsigned longで型宣言が必須 (2)1byte単位でのメモリ操作が必要 以上の2点をこなそうとするのであれば、設計ミスです。 (一応出来なくはありませんが、面倒な処理を必要としバグ要因となるため駄目です。たとえ意図した動作であっても、第三者が見ればバグソースとして指摘さる危険性が含まれます) まず、unsigned long型は32bit(4byte:0~4294967295)整数型の宣言です。 ポインタでの宣言を行う場合も、格納先アドレスそのものはCPUに依存しますが、その先にとられるメモリ範囲は32bit分を必要とします。 アドレス:0xb7de1000にlong型変数a を割り当てた場合 0xb7de1000 ←8bit(1byte) 0xb7de1001 ←8bit(1byte) 0xb7de1002 ←8bit(1byte) 0xb7de1003 ←8bit(1byte) 計32bit(4byte)を消費します。(ここは既に説明されてますね) ----------------- ex) unsigned long *a: 0xb7de1000 a+1 : 0xb7de1004 ---------------- この「a+1」処理では、置き換えると「0xb7de1003+1」ということになるのでプログラム的な回答は「0xb7de1004」で正しいということになります。 それに対して後述された処理 ================ char *a: *(unsigned long*)(a+1)=ffffffff ================ これであれば、 「a+1」を置き換えると「0xb7de1000+1」となり、アドレスについてはスマートかつ判りやすくなります。ただ書式としては、若干強引に見えますし、「何故、char型をlong型にキャストして32bitの値を入れているのだろう?」という疑問を持たせる内容と感じてしまいます。 また「キャスト=型変換」という風に訳されますが、実際には整数型を実数型にしたりコマンドの戻り値を変換したりするのに使う程度です。 「*(unsigned long*)(a+1)=ffffffff」というのは、苦肉の策だったと思いますが、この場合はchar型で必要サイズ分の配列を取得しメモリ操作系のコマンドを使用するのが素直でかつ優しいソースになると思われます。 同じ値を指定バイト数格納するのであれば「memset」が有効です。 不定値を指定バイト数格納するのであれば「memcpy」が有効です。 以上の二つについてはネット検索していただければすぐに出てきますので、割愛させていただきます。 (外部デバイスへのメモリ割り当てだと、エンディアンも絡むと思いますので留意してください。)

runjump
質問者

お礼

大変参考になりました.ありがとうございます. デバイス側のアドレスは,32ビットを扱うならば4の倍数ごとにレジスタのアドレスを設定しなければならないと言うことですね. アドバイスして戴いたように char *ADDRESS; OFFSET 0x000001; unsigned long * ptr; unsigned long data; で ptr=(unsigned long *)(ADDRESS+OFFSET); *ptr=data が memset(ADDRESS+OFFSET,data,4); の1行でおさまるようになりました. memsetはこんなときに使うのですね.勉強になりました. 本当にありがとうございます.

runjump
質問者

補足

どうもプログラムが動かないと思ったらこんな時間に… 私が求めていたのはmemsetではなくmemcpyでした. memsetはint型の引数をとるのですが下位1byteでメモリを埋めるようです. 以下確認プログラムです. #include <stdio.h> #include <string.h> #include <stdlib.h> void display(char *); int main(){ char x; char *a; long *ptr; long data; a=&x; data = 0x12345678; printf("******cast*********\n"); ptr = (unsigned long *)(a+1); *ptr=data; display(a); printf("\n******memset*******\n"); memset(a+1,data,sizeof(data)); display(a); printf("\n******memcpy*******\n"); memcpy(a+1,&data,sizeof(data)); display(a); return 0; } void display(char *a){ int i=0; for(i =0; i<6;i++) printf("a_%d %p : %x\n",i,a+i,*(a+i)); } 結果 ******cast********* a_0 0xbfe2d017 : 0 a_1 0xbfe2d018 : 78 a_2 0xbfe2d019 : 56 a_3 0xbfe2d01a : 34 a_4 0xbfe2d01b : 12 a_5 0xbfe2d01c : 23 ******memset******* a_0 0xbfe2d017 : 0 a_1 0xbfe2d018 : 78 a_2 0xbfe2d019 : 78 a_3 0xbfe2d01a : 78 a_4 0xbfe2d01b : 78 a_5 0xbfe2d01c : 23 ******memcpy******* a_0 0xbfe2d017 : 0 a_1 0xbfe2d018 : 78 a_2 0xbfe2d019 : 56 a_3 0xbfe2d01a : 34 a_4 0xbfe2d01b : 12 a_5 0xbfe2d01c : 23 自分の未熟さをおもいしりましたorz

その他の回答 (3)

  • Tacosan
  • ベストアンサー率23% (3656/15482)
回答No.3

おっととと. #2 を見て思い出したんですが「1byte」という単位そのものが処理系定義でした. ということで, #1 の「C の仕様上, 無理」というのは忘れてください. ごめんなさい. 実際, (存在するかはさておいて) 「1byte = 32bit という処理系」なら #2 の「因みに」以下の格納方法になります... が, 「unsigned long * に +1 を加えるとアドレス値が 4 増える」という記述から (unsigned long が 4byte である, つまり) そのような処理系でないことになります. で, あとは #1 の後ろの通り.

runjump
質問者

お礼

有難うございます。 ポインタはいつもいつもなやませてくれます。 まだ基本的なことが全然わかってないみたいです。

  • SAYKA
  • ベストアンサー率34% (944/2776)
回答No.2

???? そんな事できないでしょ 0xb7de1000 : ff 0xb7de1001 : ff 0xb7de1002 : ff 0xb7de1003 : ff っていう格納の仕方だもん。(実際はちょっと違うんだけど概念だけね) それで「0xb7de1001」「に」「32bitで」値を入れるなんてしたら 0xb7de1001 : ff 0xb7de1002 : ff 0xb7de1003 : ff 0xb7de1004 : ff っていう事になるよ。(これがやりたいのかもしれないけど) そうすると本来0xb7de1004はa[1]の開始地点なんだけど値が壊れる事になる。 なのでこれは危ないし手法としては行儀が悪い事このうえないね。 因みに 0xb7de1000 : ffffffff 0xb7de1001 : ffffffff 0xb7de1002 : ffffffff 0xb7de1003 : ffffffff って格納されていると思っているならそれは誤り。1byteずつしか格納されてない。

runjump
質問者

補足

回答有難うございます。 実は外部デバイスのアドレスをmmapでPC上のアドレスに割り当てて書いています。 たしかに勘違いしていました。 アドレスは1バイトずつわりあてられているということですね。

  • Tacosan
  • ベストアンサー率23% (3656/15482)
回答No.1

C の仕様上, 無理. どうしてもキャストが必要になりますし, 1 を加えた結果不適切なアドレスになった場合には未定義動作となります.

関連するQ&A