キャストに関してのまとめ

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

キャストに関してのまとめ

#1

投稿記事 by Nior » 2年前

C言語のキャストに関して、以下のようにまとめました。

キャストには以下の三つに分類される
1. 型変換→型を変更し、メモリ上の値も変更する
2. 型変更→型のみ変更し、メモリ上の値はそのまま
3. const外し

itoa などは 1 に分類される。


https://www.s34.co.jp/cpptechdoc/article/newcast/
のサイトも参考にしたのでこれは間違ってないと思っています。


問題ないかどうか、皆様りご意見もお聞かせ頂ければと思います。

かずま

Re: キャストに関してのまとめ

#2

投稿記事 by かずま » 2年前

規格書によると、型変換には暗黙の型変換と明示的な型変換があり、
キャストというのは、キャスト演算子を使った明示的な型変換のことです。

itoa は、ウィキペディアにもあるように、非標準の Cライブラリ関数であり、
キャスト演算子ではないので、あなたの分類には当てはまりません。

また、メモリ上の値を変更するのは代入や初期化によるものであり、
型変換にはメモリ上の値を変換する機能はありません。

型変換が実行される場合の、オブジェクトのビットパターンが変更
されるのをメモリ上の値を変更すると言ってしまったのでしょうね。

inemaru
記事: 108
登録日時: 3年前

Re: キャストに関してのまとめ

#3

投稿記事 by inemaru » 2年前

C++のキャストについては、ここ読むと良いと思います。
http://ezoeryou.github.io/cpp-book/C++1 ... xpr.typeid
http://ezoeryou.github.io/cpp-book/C++1 ... #expr.cast
オフトピック
Nior さんが書きました:C言語のキャストに関して、以下のようにまとめました。
質問内容的に、大きな影響はなさそうだけど、
C言語とC++は区別されるべき、
Nior さんの提示しているページはC++についてかかれている。

Math

Re: キャストに関してのまとめ

#4

投稿記事 by Math » 2年前

>その意味でreinterpret_castは非常に危険なキャストといえるでしょう。
とサイトにありますが
https://msdn.microsoft.com/ja-jp/library/e0w9f63b.aspx
”また、整数型から任意のポインター型への変換およびその逆の変換を許可します。”
でないとアセンブラでプログラムを組んでEPROMライターで書き込んでいた者としては”ポインターはアドレスで2進数に他ならないから整数型だったよな?”と思うのですが。C言語のポインターには騙される気がする...。..imo..(in my opinion)
(アセンブラに型はなく全部2進数だったかな..)

Math

Re: キャストに関してのまとめ

#5

投稿記事 by Math » 2年前

今のWinndowsOS(WindowsNT ver10.0)はDECの大型コンピューター系のOSであり[WindowsNT系:20年位前PDP-11を開発したカトラーによって開発された]
https://ja.wikipedia.org/wiki/%E3%83%87 ... 9%E3%83%BCkernelとはその中枢である。https://ja.wikipedia.org/wiki/%E3%82%AB ... D%E3%83%AB
(そのDECの大型コンピューター系PDP-11はビル・ゲーツが中学生のころ母親のこれからはコンピューター時代だと教育され近くの会社に頼んで空いた時間に”BUGをとってレンタル料を下げる”という約束で使った伝説の機械です。そこでBUGをみつけ何とレンタル料がただになった!。)
(C言語の3項演算子はPDP-11の機械語に由来する)
Linuxは”リーナス・トーバルズ”の開発し今や大型コンピューターからTVまで多数使われるUnixです。
https://ja.wikipedia.org/wiki/%E3%83%AA ... B%E3%82%BA
それらの仕組みではたくさんのプロセスがタスクスケジューラーによって動いており仕組みはそれぞれの特許である。(Unixはカーネルの特許が複雑でトーバルズは特許にかからぬよう一から開発しなおした)
それに並列コンピューティングの話にはそうゆう仕掛けではなく”ドライバー”によって駆動されるのであってプロセスとか呼ぶものとは何のことか不明。
我々のあずかり知らぬ世界でありこういうことは製造元の https://devtalk.nvidia.com/default/ に聞くこと。(秒進分歩の世界なので今日の常識は明日の非常識です。どんな簡単なことでもメーカーに聞くと変わっていることが多い。富士通さんにはリモコンではいってもらってきけるので殆んど毎日電話している。昨日もWindows10でDesktop表示がおかしくなったので見てもらったら”タブレット・モード”になっていた...。

Math

Re: キャストに関してのまとめ

#6

投稿記事 by Math » 2年前

大変失礼いたしました。間違えました。m(--)m

Math

Re: キャストに関してのまとめ

#7

投稿記事 by Math » 2年前


キャストは次のように決まります。
1.dynamic_cast, const_cast の場面ではそれを使う
2.使えるなら、 static_cast
3.どれにもあわなければ、 reinterpret_cast

static_cast は暗黙的な変換がある場合などコンパイラーにとって予測可能な変換の時に使うキャストです。
コンパイラーは変換方法はわかってますが、情報落ちが発生する変換や int から列挙型、 void * の変換などでは危険が伴うためにエラーや警告を出します。 その危険を承知した上で変換するとコンパイラーに伝えるのが static_cast です。

それに対して reinterpret_cast はコンパイラーとしては「そんなことはするなよ」といいたいようなキャストです。
reinterpret_cast にほとんど制限はなく、他の 3 つのキャストに当てはまらない時の奥の手ともいえるキャストです。

そういった reinterpret_cast を使わざるを得ない場面はというと、次のような場合が考えられます。
1.ポインタのアドレス値を整数型の変数に格納
2. double * から int * など違う型のポインタの変換

このような処理は効率を考えた場合に必要となってくる場合があります。

double の変数から int へのキャストであれば、コンパイラーは適切に処理して変換できます。 ただ、 double * から int * への変換といったポインターのキャストとなると、 double の構造を持つ変数を int として処理するわけですから、普通は不定の動作をしてしまいます。 これはコンパイラーにとっては「何でこんなことやっているの!?」というような処理だと思います。

しかし、このような変換もメモリとして扱う場合には使えます。
例えば、次のような場合でしょう。
•バイトスワップで double の値を unsiged long long にする
•バイナリファイルの読み取りで char 型の配列で用意したバッファーに構造体を格納する
ただ、これは一回 void * を経由すれば、 static_cast で書けることが多い。
そうすると純粋なメモリとして扱うための処理だよということをコンパイラーに知らせることになります。

Math

Re: キャストに関してのまとめ

#8

投稿記事 by Math » 2年前

C 言語では定数は「定数型の変数」の事です。 定数型というのは、普通の型に「const」という型修飾子を指定した物のです。 値が設定出来るのは初期化の時だけです。const int N=12345; int x=N;とすればxはconst が外れた型にキャストされます。
const なポインタはややこしく const int* p=NULL; p=new int; は OK で *p=123;はエラーになります。
p は int 型への定数ポインタではなく 「const int 型への」ポインタなのです。
定数ポインタ (constant pointer) を宣言するにはint* const p=...; とします。更に、定数への定数ポインタ const int* const も可能です。
さて、実は「int const *」等という表記も可能です。 実はこれは「const int*」と同じ意味で、「int *const」ではありません。
<const の結合則> 1.出来るだけ左側にある型にくっつきます。2.左側になにもない時に限って、右側の型にくっつきます
---
int const v1;
const double& r1;
int * const * * const ppp;

/* 頭の中で
int|* const|*|* const ppp;
と区切ることが出来れば大丈夫
*/
答えというか日本語にすると、v1 は "定数な int" です。 r1 は "定数な double への参照" です。 ppp は "int への定数ポインタへのポインタへの定数ポインタ" です (日本語にすると訳が分からなくなります)。 実際に ppp の様な型は殆ど出てきませんが、int* const* const 位なら出てくるかも知れません。 そう言う時は、全体を見ては行けません。最後の "* const" の部分だけを見る様にしましょう。 前の方に付いているごにょごにょは、"* const" のポイント先の型を説明しているに過ぎないのですから。
---
暗黙的に変換可能な物は以下の通りです。
•const 型の値→非 const 型の値
•非 const 型の値→const 型の値
•非 const 型へのポインタ→const 型へのポインタ
•非 const 型への参照→const 型への参照

値には const も非 const もありませんので、自由に行き来が可能です。 但し、値の場合にはメモリ上で値のコピーが生成します。 また、ポインタや参照型に const を追加するのも、「代入の操作を制限するだけ」なので問題ありません。 ポインタや参照の場合には、ポインタ・参照自体のコピーは発生しますが、 その指し示している先のデータのコピーは発生しません。
---
変換しようと思ったら、明示的に変換しなければならないのは以下の変換です。
•const 型へのポインタ→非 const 型へのポインタ
•const 型への参照→非 const 型への参照

const 型へのポインタや参照というのは、「変更しないでね」という意味を込めたポインタ/参照です。 それを、変更できるようにしようと思ったら、特別な事情か配慮がなければなりませんので、 明示的変換を要求されているのです。
---
(あ、頭がくらくらする...。)

返信

“C言語何でも質問掲示板” へ戻る