5: 2007-03-17 (土) 22:25:26 |
6: 2007-03-22 (木) 19:20:56 |
| | | |
| | | |
| + | こんなふうに考えるとわかります。アドレス。文字通り、''住所・番地''です。 |
| | | |
| + | -たとえばアナタの住んでいる所。住所がありますよね?。で、その住所。数字も使われているでしょう? |
| + | -日本国 東京都 葛飾区 亀有 5丁目 18番地 とか。 |
| + | -こういう住所の数字に対して、「なあ?お前の家の住所の三倍ってなに?」ともし聞かれたらどう答えますか? |
| + | -「まずよく寝ろ!話はそれからだ」が正しいですね? <はぁ??? |
| + | -つまり、住所にはたまたま数字が使われていますが、これは倍にしたり割り算したりするようなものではない。つまり、''数字は使っているけど数値ではない''となります。 |
| | | |
| + | 上記の例がエラーになるのはこれが理由です。int(4バイト)だろうがchar(1バイト)だろうが、これらは数値なのです。なので、「住所の番地に数を代入しようとしてるぞ!おかしいぞ!」と、こういうことでエラーになってしまうのです。 |
| | | |
| | | |
| + | そのため、こういう代入をしたい場合は、数値であるiを''型キャスト''して、一時的にアドレス変数タイプに転換してから代入してやる必要があります。 |
| | | |
| + | この場合、何型にキャストしてあげればいいでしょう。pと同じにしてあげればいいのです。変数pはchar型です。しかも、*がついています。char型のアドレス変数(ポインタ)です。なので、 |
| | | |
| + | char *p; |
| + | char a; |
| + | int i; |
| | | |
- | ---- | |
| | | |
| + | for(i = 0x0010; i = 0x0014; i = i+1) |
| + | { |
| + | p = (char *)i; /* ←ここに注目!*/ |
| + | printf("データは %d 16進数だと %x だよーん!\n",*p); |
| | | |
| + | } |
| | | |
| | | |
| + | こうしてあげれば、int変数であるiは一時的にアドレス変数pと同じ型に変化します。よって代入が可能になり、エラーが出なくなります。 |
| | | |
| | | |
| + | もう一度書きますが、アドレス変数(ポインタ)は、たまたま数字を使っているだけの住所番地です。よって、足したり割ったり掛け算したりできる''数値''とはまったく違う型なのです。 |
| | | |
| + | -COLOR(BLUE){ちょっとまて!それはおかしいぞ! この状態で p = p + 1 等の演算をしてもエラーにならないはず。アドレス変数だって計算が出来る''数値''じゃないのか??} |
| | | |
| + | -COLOR(red){大変すばらしい問いです。ほんとですね。アドレス変数であるpに対して、足し算・引き算を行うことはできますしエラーにはなりません。やっぱりアドレス変数も''数値''なのでしょうか???} |
| + | -COLOR(red){では、実験してください。p = p * 3 等、掛け算や割り算をしてみてください。ほらね?エラーになるでしょう??。これはいったいどういうことなのでしょうか?} |
| + | -COLOR(red){難しく考えることじゃありません。たとえば最初に出した、実際の住所・番地で考えてください。} |
| + | --COLOR(red){あなたの住所は「日本国 東京都 葛飾区 亀有 5丁目 18番地」です。この住所に対して、「お前の住所の2倍」というのは成り立ちません。} |
| + | --COLOR(red){しかし、「お前の住所の次」はどうですか?} |
| + | --COLOR(red){「お前の住所の3軒前の家」ならどうでしょうか?。} |
| + | --COLOR(red){そう。成り立ちますね?} |
| + | -COLOR(red){つまり、アドレス変数が足し算引き算はできても掛け算割り算ができないのはこういう理由なのです。そしてこの理屈なら、足し算ができたってやっぱりアドレス変数は''数値''ではないということも矛盾しないでしょう?} |
| + | -COLOR(red){もっと言えば、アドレス変数(ポインタ)を p = p + 2 などとしているのは「2軒後のお家」と言っているだけで、そもそも''足し算ではない''とさえ言えます} |
| | | |
| | | |
| | | |
| | | |
| + | *現実の型キャスト [#x0b20a5e] |
| + | さて、これまで書いたことは、あくまでも概念と理屈の理解のためです。実際のCでは上記そのままではありません。(もちろん理屈そのものは合っているはずです) |
| | | |
| + | **数値の型キャスト [#k48737ef] |
| | | |
| + | たとえばこんな式を考えます。 |
| | | |
| + | char z; |
| + | char c; |
| | | |
| + | z = 0x44; |
| + | c = 0x22; |
| | | |
- | ・・・しかし、これでは問題が出てしまいます。そう、 ''p = p + i;''の部分です。 | + | c = c + z; |
| | | |
- | もうお解りですね。これは、 p(ポインタ型) + i(int型) の足し算になります。実際の足し算の値にはなんの問題もないのですが、異なる型同士の演算ということなので問題になるのです。 | + | printf("data is %x\n",c); |
| | | |
- | じゃ、どうするか?。簡単です。 この足し算の時、一時的に変数iをポインタ型にキャスト(型変換)してやればいいのです。 | + | 答えは暗算できますね。結果は0x66になります。もちろんエラーも出ません。同じ型同士の足し算を同じ型に代入したのですから当然ですね。 |
| | | |
- | この変数pはポインタ型。さらに言えば、「char *」型の変数ですね。なので、'' (char *)i''としてやれば、変数pと同じ型になります。よって、 | + | ではこんな式はどうでしょう? |
| | | |
- | char *p; | + | int i; |
- | char a; | + | |
- | int i; | + | |
| | | |
- | p = 0x0010; | + | char z; |
| + | char c; |
| | | |
- | for(i = 0; i = 4; i++) | + | z = 0x44; |
- | { | + | c = 0x22; |
- | p = p + (char *)i; /*これで変数iは一時的にchar *型のポインタ型になる*/ | + | |
- | printf("データは %d 16進数だと %x だよーん!\n",*p); | + | i = c + z; |
- | } | + | |
| + | printf("data is %x\n",i); |
| + | |
| + | これまで説明してきた「概念」ではこれはおかしいはずです。だって、変数zと変数cはchar型。しかし代入しているiはint型。型が合わないはずです。''ところが・・・'' |
| + | |
| + | あれれれ〜? これをコンパイルすると、ちゃんと''エラーもなく''、さらに実行してもちゃんと答えが出てきます。どういうこと??? |
| + | |
| + | 実はこれは、厳密には概念通り、型が合わないのです。しかしCコンパイラは、「この程度ならよく使うし、いちいち型キャストの警告出しててもうっとぉしいだろうなぁ。この程度は容認してあげよう」と考えるように調整されているのです。 |
| + | |
| + | -COLOR(blue){もちろん、 i = (int)c + (int)z; と書いても当然エラーにはなりません。むしろこれが正しいのです。''本来の概念''で言えば。} |
| + | |
| + | もちろん「許容」にもちゃんと法則があります。これには順番があります。以下を順番に適用していくのです。 |
| + | -最後は左辺の型に自動調整される |
| + | |
| + | |
| + | です。 |
| + | |
| + | こんな式を妄想してみます。 |
| + | |
| + | char c; |
| + | int i; |
| + | short s; |
| + | double d; |
| + | |
| + | c = 0x11; |
| + | i = 0x22; |
| + | s = 0x33; |
| + | d = 0x44; |
| + | |
| + | i = c + i + s + d; |
| | | |
- | こうすることで、型違いの演算という問題は出なくなります。 | + | printf("data is 0x%x\n",i); |
| | | |
- | COLOR(red){念のためもう一度言いますが、こういう処理を実際にプログラミングする場合、こんなコードは書きません。単純化するためにこんなことかいてますので。} | + | さあ、この計算は型が混在もいいところですね。でもエラーは出ません。Cコンパイラが「許容」しているためです。 |