• ベストアンサー

ポインタの演算について

ポインタの演算に関して質問させて下さい。 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

  • ポインタ演算がうまくできません

    以下のソースを実行すると、直値でアドレスをしていするのは うまくアセンブラに展開され、意図するアドレスを取り出す ことが出来るのですが、変数でアドレス演算させると意図する アドレスが取得できません。  何か記述がおかしいのでしょうか? ご存知の方宜しくお願い致します。 char const test_tbl[] = { -3, -2, -1, 0, 1, 2, 3, 4, 5}; unsigned char *ptr; unsigned char work; #define STA_OFFSET (&test_tbl[3]) void main( void) { // 適切なポインタが取得できる ptr = (STA_OFFSET + 3); // ポインタが取得できない。 work = 3 ptr = (STA_OFFSET + work); }

  • ポインタ代入のoperator演算子のオーバロードの仕方

    下記、unsigned char*型を自前のクラスで作成した場合 どの様なoperator演算子が必要になりますでしょうか。 目的は、下記compにアクセスした回数をカウントさせたい為です。オーバロード関数の内部にカウンタを持たせたい。 unsigned char* と互換性を持たせるため、クラスはポインタとして定義して使用したいと思っています。 unsigned char comp[1000] ; int main( int, char** ){ unsigned char *v_ptr ; v_ptr = &comp[0] ; <- ここ *v_ptr = (unsigned char)100 ; <- ここ *v_ptr++ = *sw_ptr++ ; <- ここ return 0; } 下記のように使いたい unsigned char comp[1000] ; int main( int, char** ){ count * v_ptr ; v_ptr = &comp[0] ; <- ここ *v_ptr = (unsigned char)100 ; <- ここ *v_ptr++ = *sw_ptr++ ; <- ここ return 0; } class count{ public: unsigned char* operator*() { return ptr ; }  v_ptr& operator=()?? private: unsigned char* ptr ; } ; 色々調べてみましたが、自前クラスが右辺にある時のポインタ、アドレスオーバロードはありましたが、左辺のポインタ代入、値代入を見つける事が出来ませんでした。

  • C言語signed long long型の演算

    C言語で以下の演算を行った場合、変数bに格納される値が-1(0xFFFFFFFFFFFFFFFF)になることを期待しておりましたが、参照すると4294967295(0x00000000FFFFFFFF)となってしまいます。 unsigned int a = 1; signed long long b; b = a * (-1); 32bit、64bitのUNIX(Solaris)マシンでそれぞれ確認しましたが、どちらも同じ結果となりました。 変数aの型宣言をsigned intにすると変数bが-1(0xFFFFFFFFFFFFFFFF)になることは確認したのですが、unsigned intだとなぜこのような演算結果となるのかが分かりません。 ※8バイト整数に格納する際に先頭4バイトがなぜ0xFFFFFFFFで補完されないのか? ちなみに変数bの型宣言をsigned long intにすると32bitマシンでは-1となりましたが、64bitマシンでは4294967295となってしまいます。 これは32bitUNIXマシンではsigned long intは4バイト領域であるため-1(0xFFFFFFFF)となり、64bitUNIXマシンでは8バイト領域のため前述と同じ結果になるのだと考えますが、なぜ8バイト整数を使用するとこのような演算が行われるのかが分からないので、演算順序や型変換の優先順位がどのように行われいるのか説明できる方教えてください。

  • ポインタのキャスト

    配列の先頭アドレスをunsigned long型で取得するにはどうしたら良いでしょうか? 下記だとダメですよね? char a{4} = [0, 1, 2, 3]; unsigned long adr; adr = (usigned long)&a[0]; よろしくお願いします。

  • ビット演算について

    いつもお世話になります。 ビット演算について教えて下さい。 unsigned char buf1[1]=0x5a unsigned char buf1[2]=0x04 unsigned char buf1[3]=0x38 5a0438(16)を3バイトの値を12ビットずつの整数で得るにはどうしたらいいのでしょうか? 2進数表記では、 5A | 04 | 38 01011010 | 00000100 | 00111000 12ビットずつとは、 010110100000 010000111000 と区分し、10進数の整数値で得たいです。どのようにすればよいでしょうか? また、0x5Aなどの16進数を2進数のビットで考えるときに、 01011010を下位4ビットを10進数整数を得るにはどうしたらよいのでしょうか? 上記2点、どうぞよろしくお願い致します。

  • ポインタ

    long ToLittleEndian(char *a,long bytesize){ long i; char lb; char hb; long lsize; lsize=bytesize/2; for (i=0;i<lsize;i++){ hb=*(a++); lb=*(a--); *(a++)=lb; *(a++)=hb; } return 0; } ポインタのアドレスがはみだすとどうなるのでしょうか? 上記のようなコードの場合、最後の処理でポインタaが1バイト分はみ出してしまいますが、 存在しないアドレスを参照しようとするとエラーになるかと思いますが ポインタを動かすだけだと問題ないのでしょうか? 処理系やコンパイラに依るのでしょうか。 初心者ですがよろしくお願いします。

  • 文字を整数として扱う場合の演算について質問

    javaの参考書に、文字を整数として扱う場合の演算についての解説があり、疑問点があったので質問します。 質問1:何故char型の変数は、キャストしなくてもint型のリテラルを代入することができるのか?      例えば、 以下の演算はキャストしなくてもこのまま代入できます。 char ch='a'; ch=98; でも、以下の演算はキャストしていないのでエラーになります。      char ch='a'; ch=ch+1; これは何故ですか?参考書に記載されていた理由として、「byte,char,short、 これ等の型の変数や値を使って計算すると、それ等は一度intに直して計算されるから」というような趣旨の事が書いてありました。 つまり、char型の変数には、キャストしない限りint型の数値を代入できないということですよね? でも前者のソースコードは、chはchar型であるにもかかわらず、int型のリテラル98を代入できています。 これは何故ですか? 質問2:javaの参考書に、インクリメント・デクリメント演算子と複合代入演算子は、型を保存するという解説がありました。これはどういう意味ですか? 僕の仮説では、例えば、      char ch='a';      ch+=5; であれば、5は、char型のまま代入されるということでしょうか?

    • ベストアンサー
    • Java
  • 値のコピーについて

    お世話様です。 unsigned long aaa(32bit)にunsigned char bbb[4](8bit*4)を コピーする場合に、(1)と(2)で結果が違うのはなぜでしょうか? よろしくご教授お願いいたします。 (1)memcpy(&aaa bbb, 4); (2) { aaa = 0; unsigned long ccc = 0; ccc = static_cast<unsigned long>bbb[0]; aaa |= ((ccc << 24) & 0xFF000000); ccc = static_cast<unsigned long>bbb[1]; aaa |= ((ccc << 16) & 0x00FF0000); ccc = static_cast<unsigned long>bbb[2]; aaa |= ((ccc << 8) & 0x0000FF00); ccc = static_cast<unsigned long>bbb[3]; aaa |= ((ccc << 0) & 0x000000FF); } 【環境】CPU:Pentimum4 OS:WindowsXP コンパイラ:VC++8.0

  • 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個用意されるのでしょうか? お願いします。

  • c言語 等価演算子(==)について

    等価演算子(==)は、ポインタの指すオブジェクトが同一あるかないの判定する演算子。  故に下記の例、*sc1 == sc2 は、sc1とsc2の値(オブジェクト)を比較しているのですか教えてください。      char *sc1 = s1; char *sc2 = s2; *++sc1 == sc2;