質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Q&A

解決済

4回答

6394閲覧

明示的なキャストとアライメント調整の注意点

strike1217

総合スコア651

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

0グッド

1クリップ

投稿2017/01/20 09:12

編集2017/01/20 11:33

以下のような実験コードを作りました。

C

1#include<stdio.h> 2 3int main(){ 4 double x; 5 double* pd; 6 7 char* pc = &x; 8 pc++; 9 pd = (double *)pc; 10 11 printf("pc = %p\n", pc); 12 printf("pd = %p\n", pd); 13 return 0; 14}

すごく簡単にするために
pcのアドレスは 8 とします。
pc++ で 9となります。

pd = (double *)pc; こいつです!

doubleが8バイトの境界調整をもつならば、9というアドレスは中途半端です。
この場合、pdのアドレスは8 もしくは 16 になる可能性があるそうです。

実際にやったら、アドレスが同じになりました。 pc = 003DFB81 pd = 003DFB81

char* pc = &x;
これは、「暗黙的にキャストが行われている」と思います。

pd = (double *)pc;
こちらは、「明示的にキャストが行われています」(多分)

1、この2つ(明示的キャスト、暗黙的キャスト)正直何が違うんですか?? 明示的にキャストする場合としなくても良い場合の違いがわかりません。C/C++でも違いがあるそうですが・・・
2、アライメントを考慮すると「暗黙的、明示的関係なく、ポインタを別の型のポインタへのキャストする」のは控えた方がよろしいんですかね???
3、この実験コードに修正箇所があれば、教えてください。

[追記]
実験したのはwindowsです。
visual studioでオプションは何も入れないで、clコンパイルしています。

[追記2]
私のC言語の本にこう書いてあります。

ポインタを他の型へのポインタに型変換することは、その値までもが変わる可能性のある危険な行為であり、注意深く行わなければならない。型や型変換に対して厳密なC++が、voidへのポインタを別の型のポインタに代入する局面で明示的なキャストを必須としているのは、このような危険を避けるためです。

えーーーと
明示的なキャストすることで、どうしてポインタを他の型へのポインタに変換する際の危険性を避けることができるのでしょうか??

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答4

0

ベストアンサー

「暗黙的にキャストが行われている」と表現されてますが、コンパイルすると「互換性のないポインターだよ」とコンパイラーが警告を発すると思います。

型が違うポインターどうしての代入などの演算はプログラマーになんらかの意図があるはずであり、質問者さんがおっしゃる「暗黙的キャスト」は避けるべきコーディングです。そのまま警告を放置するなら何かが起こるのでしょうがそれを気にすること自体はあまり有意義なことではないと思います。
char*->double*への明示的なキャストについて考えてみますと「double型のアドレスとして妥当なアラインメントであるかをプログラマーが意識した上で敢てキャストする」と考えるのが普通だと思います。ではわざとアラインメントがおかしなキャストをしたとしたらどうなるかですが、現在のclangの規格で何か規定があるのかどうか自分は知りません。

手元のcygwin64でgcc使ってやってみるとアラインメントが適切でないポインターがdouble*変数へそのまま代入されてました。この状態で何がおこるかは自分が知る限りプロセッサの種類によって異なり、アラインメント例外を発するプロセッサと、いわれたとおりに動いてしまうプロセッサに大別されると思います。例えばインテルのプロセッサは後者だったと思います。ただ記憶装置(メモリー)は語境界でアクセスする前提で作られているのでプロセッサがアライメント境界をまたぐメモリーアクセスを許す場合、メモリーのアクセスが2回行われてプロセッサー内部で前半分と後ろ半分のデータをガッチャンとビット連結して結果を作る動作をするので「遅い」と思います。

いずれにせよアラインメントについて普通でないことをするとしたらプロセッサーとコンパイラーの動作をよく把握して何か特別な意図(あまり思い浮かびませんが)でやらない限り一般的には避けるべきコードであると言えましょう。

投稿2017/01/20 10:15

編集2017/01/20 12:55
KSwordOfHaste

総合スコア18392

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

strike1217

2017/01/20 10:19

mit0223さんと同じく、やはり避けるべきなんですね! ん~~~ この辺りは難しいですね・・・
strike1217

2017/01/20 10:22

「暗黙的キャスト」は避けるべき 今後は注意してプログラミングします。
guest

0

1、この2つ(明示的キャスト、暗黙的キャスト)正直何が違うんですか??

コードを Mac OS と CentOS でコンパイルしてみましたが、暗黙的キャスト?と言われているほうは、両方ともワーニングになりました。基本的にポインタを別の型へのポインタに変換する場合は明示的にキャストする必要があると思います。

2、アライメントを考慮すると「暗黙的、明示的関係なく、ポインタを別の型のポインタへのキャストする」のは控えた方がよろしいんですかね???

理由がなければキャストは利用しないでしょう。普通はキャストの必要があるからキャストするわけで、「控える」というような問題ではないと思います。ポインタのキャストもC言語のプログラム上では一つのコーディングテクニックです。ただし、

doubleが8バイトの境界調整をもつならば、9というアドレスは中途半端です。

この場合、pdのアドレスは8 もしくは 16 になる可能性があるそうです。

このことは知っておいたほうが良いでしょう。たとえば、ファイルの中から読み込んだ char [] 型のバッファの途中に double でデータが入っていることがわかっているときに、その場所からポインタをキャストして読み出すことはできないということですね。C言語の仕様書に「動作は不定である」と書かれているので、たとえ、どっかのパソコンで動作したとしてもこのようなコーディングは控えたほうが良いでしょう。

投稿2017/01/20 10:07

mit0223

総合スコア3401

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

strike1217

2017/01/20 10:12

ありがとうございます。 実行環境を追記しておきますね
mit0223

2017/01/20 10:17

後からこの質問を見た人のためということであれば、実行環境だけでなく、コンパイラとそのバージョンとコンパイルオプションを追記いただいたほうがいいです。
mit0223

2017/01/20 10:30

すみません。後学のために一つ確認ですが、 Visual Studio のデフォルトでコンパイルすると、double* -> char* の暗黙的なキャストに警告メッセージはでないということで間違いないでしょうか? 警告がオプションで抑制されているとかいうこともないでしょうか?
strike1217

2017/01/20 10:34 編集

すごく、見えにくいのですが、以下のようにwarningが出てきます。 source3.c(7): warning C4133: 'initializing': incompatible types - from 'doubl *' to 'char *' char* pc = &x;こいつはwarningがでています。
mit0223

2017/01/20 10:35

お手数書けました。確認ありがとうございました。(安心しました)
guest

0

C++を使っているのなら、C++のキャストを使いましょう。

C++ スタイルのキャスト

投稿2017/07/21 08:15

PineMatsu

総合スコア3579

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

1、この2つ(明示的キャスト、暗黙的キャスト)正直何が違うんですか??

わかってキャストしてますよってだけでしょう。暗黙的キャストよるワーニングやエラーを消す為だけに、危険な意味もわからず、明示的キャストしても意味ない。ワーニングとかもでなくてよけい面倒。
CとC++の違いは、CではワーニングだったところがC++ではエラーになったりします。

2、アライメントを考慮すると「暗黙的、明示的関係なく、ポインタを別の型のポインタへのキャストする」のは控えた方がよろしいんですかね???

自分の想定する環境で、どういうことが起こるかわかっていれば、別にいいんではないの?わからなければ控えた方がいいと思います。

投稿2017/07/21 03:55

tmp

総合スコア277

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

strike1217

2017/07/21 03:57

ありがとうございます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問