C++のvoidポインタの明示的なキャストについて

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら

トピックに返信する


答えを正確にご入力ください。答えられるかどうかでスパムボットか否かを判定します。

BBCode: ON
[img]: ON
[flash]: OFF
[url]: ON
スマイリー: OFF

トピックのレビュー
   

展開ビュー トピックのレビュー: C++のvoidポインタの明示的なキャストについて

Re: C++のvoidポインタの明示的なキャストについて

#23

by usao » 8年前

オフトピック
銃で例えると(実物知らんから合ってるか不明だけども)
・トリガーを引いたらとにかく弾が発射される.だってあなたがトリガを引いたのですからね.それに応じるのが銃ってもんですよ.
・暴発事故が絶えないから安全装置を外さないと撃てないようにしといたぞ.
というスタンスの違いかな?
Cは前者だったけど,C++は後者側,みたいな.
ただ引き金を引こうとすると「安全装置が外れてないぞ」とコンパイラが言ってくれる.

Re: C++のvoidポインタの明示的なキャストについて

#22

by ハワルド » 8年前

C++で、ポインタを別の型のポインタに代入する際に明示的にキャストをしなければコンパイルエラーが出るのは、
それでポインタ値が変わることを防げるからではなく、
「代入に伴って、ポインタ値が変わる可能性がある」ということを処理系やプログラムを読む人に伝えるべきだからということですね!

Mathさん、伊藤詩織さん、usaoさん
ありがとうございました!

Re: C++のvoidポインタの明示的なキャストについて

#21

by Math » 8年前

(C言語の先祖Bは型はWORD(要するに整数型)しかなくポインターも整数として扱っていたし仮想マシンのうえで動いていてアドレスもWORD単位に振られていたので1を加えれば自動的に配列の次の要素を指していました。Cは型が増え「ポインターに1を足すとそのサイズだけ進む」という規則になったのでポインターにはアドレスと型情報が必要になったわけです。void*を代入するとき、void* は型が汎用なのでCでは代入した型が暗黙的には使われるがC++ではキャストして代入しなさいとなったのだと思います。Cでもキャストしたほうが良いということですね...。)

Re: C++のvoidポインタの明示的なキャストについて

#20

by Math » 8年前

>...と書いてあったので、C++には他の理由があると思ったのですが、これを"書かなければいけない"と決めたというだけの話なのでしょうか・・・

結局のところそうでしょうね。

Re: C++のvoidポインタの明示的なキャストについて

#19

by Math » 8年前

そのようですね(^^;
まあCはエラーチェックがほとんどない世界なのでC++の方が少し良くなってるということでしょうね。

Re: C++のvoidポインタの明示的なキャストについて

#18

by ハワルド » 8年前

Mathさん

すいません!コードをcに指定する事を忘れていました
僕の環境でもpcとpdは同じになったのですが、
コラムに実行結果一例としてpc=9 pd=16とあったので、変わってしまうことがあると理解しました
僕の環境と、想定している環境が違っているからpcとpdが同じになったのだと思います

Re: C++のvoidポインタの明示的なキャストについて

#17

by Math » 8年前

>このプログラムでは、char*型を例にとって説明しましたが、void*型は1バイトの境界調整をもち、
>任意のアドレスを指すことができるという点ではchar*型と共通です
1バイト単位でアドレスがかわるにしてもvoid*に代入して 同じ型のデータとして取り出せばいいのだから まあこういう使い方をしないように!ということではありますよね。

Re: C++のvoidポインタの明示的なキャストについて

#16

by Math » 8年前

文章からC++の例と勘違い。Cだとこのようになりました。

コード:

1>------ すべてのリビルド開始: プロジェクト:Win32ConsoleApplication0830, 構成: Debug Win32 ------
1>c1.c
1>d:\z17\cpp\001\01\win32consoleapplication0830\win32consoleapplication0830\c1.c(9): warning C4133: '初期化中': 'double *' と 'char *' の間で型に互換性がありません。
1>Win32ConsoleApplication0830.vcxproj -> D:\z17\cpp\001\01\Win32ConsoleApplication0830\Debug\Win32ConsoleApplication0830.exe
1>Win32ConsoleApplication0830.vcxproj -> D:\z17\cpp\001\01\Win32ConsoleApplication0830\Debug\Win32ConsoleApplication0830.pdb (Partial PDB)
1>プロジェクト "Win32ConsoleApplication0830.vcxproj" のビルドが終了しました。
========== すべてリビルド: 1 正常終了、0 失敗、0 スキップ ==========

コード:

pc = 00D5F999
pd = 00D5F999
続行するには何かキーを押してください . . .
void* とのからみがよくわかりませんが間違った使い方でC++ではエラーにしているがCではワーニングですね。
64ビットCPUなので8バイト アライメントだと思うのですが これでどうして”境界調整というものでポインタの値が勝手に変わってしまうことがあることは理解した”のしょうか?

Re: C++のvoidポインタの明示的なキャストについて

#15

by ハワルド » 8年前

Mathさん

確認しましたが間違えていませんでした
cコンパイラでコンパイルすると警告は出ますがコンパイルは通りましたが、
c++コンパイラでコンパイルすると画像と同じようなエラーが出ました

void*型との関連は、
このプログラムでは、char*型を例にとって説明しましたが、void*型は1バイトの境界調整をもち、任意のアドレスを指すことができるという点ではchar*型と共通です
と説明されています

Re: C++のvoidポインタの明示的なキャストについて

#14

by Math » 8年前

(void* が絡むところが抜けているのではないですか。)

Re: C++のvoidポインタの明示的なキャストについて

#13

by Math » 8年前

これはWindows10,VC++2017Communityではこういうエラーになります。
画像

なにか間違えていませんか?

Re: C++のvoidポインタの明示的なキャストについて

#12

by ハワルド » 8年前

usaoさん、伊藤詩織さん

その本の最後に、
C言語では明示的なキャストが必須ではないとは言え、ポインタの値を、異なるポインタ型に代入する際は「代入に伴って、ポインタ値が変わる可能性がある」ということを、処理系やプログラムを読む人に伝えるべきです。そういう意味では、キャストが必須ではないC言語でも明示的なキャストを行うほうが好ましいといえます
と書いてあったので、C++には他の理由があると思ったのですが、これを"書かなければいけない"と決めたというだけの話なのでしょうか・・・


Mathさん

書名は 新・明解C言語中級編 です。
このコラムにはポインタを他の型へのポインタに変換すると値が変わる可能性があるということを示すために

コード:

/*ポインタと型変換*/
#include <stdio.h>

int main(void)
{
    double x;
    double *pd;
    char *pc = &x;
    pc++;
    pd = (double *)pc;

    printf("pc = %p\n", pc);
    printf("pd = %p\n", pd);
    return 0;
} 
というコードが載っていて、
実行結果 pc = 9 pd = 16
double型が8バイトの境界調整を持つ環境を想定。
とあります。

Re: C++のvoidポインタの明示的なキャストについて

#11

by Math » 8年前

そうですねC言語のように暗黙的なキャストでも普通に使っているぶんには何ともないですよね。

>その理由を境界調整で説明しています

>境界調整というものでポインタの値が勝手に変わってしまうことがあることは理解したのですが

これをもっと詳しく説明していただけますでしょうか。(よかったらCの本の書名[私の持ってる本かも]も教えてください)

Re: C++のvoidポインタの明示的なキャストについて

#10

by usao » 8年前

> ポインタを他の型へのポインタに型変換するということは、その値までもが変わる可能性のある危険な行為です。
> そのため、C++では、voidへのポインタを別の型へのポインタに代入する局面では、明示的なキャストが必須となっているのです。

「危険な行為 → なので,明示的に書け」
つまり
「危険な行為 → なので,勝手にはやらないよ」
ということではないでしょうか.

よく考えてやらないと危険なことになり得る動作が勝手に(知らぬ間に)発生してしまわないように,
「俺は危険性を承知の上でこのキャストやるのだ」と人間が明示的に書かねばならないというルールになっていますよ的な話なのではないでしょうか.

Re: C++のvoidポインタの明示的なキャストについて

#9

by Math » 8年前

なにか勘違いされていると思います。
なにかそのCの本にサンプル コードがありませんか。(コードなしで文章だけではわかりずらいですね)

Re: C++のvoidポインタの明示的なキャストについて

#8

by ハワルド » 8年前

Mathさん

メモリを確保してvoid*型にアドレスを入れてから、キャストして確保したメモリの位置を変更するのではなくて
初めからキャストされた型としてメモリを確保するということですか?
コンパイル時点でキャストが分かるから上のようなことをするのは手間がかかるだけなのかな・・・
そうだとしても、暗黙的なキャストでも明示的なキャストでも行われるのではないですか?

Re: C++のvoidポインタの明示的なキャストについて

#7

by Math » 8年前

>キャストをすれば正しいアライメントになる とは、メモリの配置を変えるということですか?
メモリの配置を変えるというよりその時点の型がきまればメモリの配置は決定してるはずなのでそれに合わせて配置されているでしょう。
(アライメントが必要ならそうされているでしょう)
void * はアドレス値なのでどんな型でも「64ビットCPUなら8バイトの値、32ビットCPUなら4バイトの値」が代入されているだけです。
(超厳密にいえば単純にアドレス値でない場合もあるそうですが普通の環境ではアドレス値です)

void型のポインタを参照するには必ず”型情報”が正しく確定していなくてはいけないですよね。

Re: C++のvoidポインタの明示的なキャストについて

#6

by ハワルド » 8年前

Mathさん

キャストをすれば正しいアライメントになる とは、メモリの配置を変えるということですか?

Re: C++のvoidポインタの明示的なキャストについて

#5

by Math » 8年前

こちらが詳しいようなので勉強中です。
http://www5d.biglobe.ne.jp/~noocyte/Pro ... nment.html

Re: C++のvoidポインタの明示的なキャストについて

#4

by Math » 8年前

普通構造体などでアクセスをやりやすく(はやく)するためにパディングをいれアライメントが思った通りではないことがありますね。
http://sscrisk.hatenablog.com/entry/20100316/1268748458

Re: C++のvoidポインタの明示的なキャストについて

#3

by Math » 8年前

>C++では、voidへのポインタを、別の型へのポインタに代入キャストがする際には、キャストが必須です。
当然キャストをしないと代入不可能と思いますが(Cは可能でもおもいきり環境破壊の恐れがありますね)
>とあり、その理由を境界調整で説明しています。
>そのコラムの最後の方に
>ポインタを他の型へのポインタに型変換するということは、その値までもが変わる可能性のある危険な行為です。
>そのため、C++では、voidへのポインタを別の型へのポインタに代入する局面では、明示的なキャストが必須となっているのです。
当然キャストをすれば正しいアライメントになるとはおもいますが。

汎用ポインタはあらゆるポインタ型に変換できるポインタ型です
多くはどのような型も受け取れる関数を作成するのに使用されます
汎用ポインタを使用すれば、ポインタ型であればどのような型でも受け取ることができます

void型のポインタを逆参照するには必ず型キャストします
キャストはC言語では任意ですが、C++では必ず必要となります
void型ポインタはどのデータ型にも変換することができます

アライメントについて
http://nagayasu-shinya.com/cpp-aligned-allocate/

Re: C++のvoidポインタの明示的なキャストについて

#2

by 伊藤詩織 » 8年前

その辺りは,このサイトで説明されているようですね.

http://www7b.biglobe.ne.jp/~robe/cpphtm ... 03004.html

完結に言うならば,「void*型の変数に入っているアドレスは,どの様な型を意図して代入されたのかが,それだけでは分からないので,明示的にキャストして使用しましょう.」というだけの話に過ぎない様に思えます.

C++のvoidポインタの明示的なキャストについて

#1

by ハワルド » 8年前

現在C言語を勉強していて、使用している本のコラムに、
C++では、voidへのポインタを、別の型へのポインタに代入する際には、キャストが必須です。
とあり、その理由を境界調整で説明しています。
そのコラムの最後の方に
ポインタを他の型へのポインタに型変換するということは、その値までもが変わる可能性のある危険な行為です。
そのため、C++では、voidへのポインタを別の型へのポインタに代入する局面では、明示的なキャストが必須となっているのです。
と書いてあります。

境界調整というものでポインタの値が勝手に変わってしまうことがあることは理解したのですが、それが明示的なキャストをすることでどのように解決するのでしょうか。

ページトップ