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

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

ただいまの
回答率

90.53%

  • C

    4382questions

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

  • C++

    4304questions

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

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

解決済

回答 4

投稿 編集

  • 評価
  • クリップ 1
  • VIEW 1,356

strike1217

score 568

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

#include<stdio.h>

int main(){
   double x;
   double* pd;

   char* pc = &x;
   pc++;
   pd = (double *)pc;

   printf("pc = %p\n", pc);
   printf("pd = %p\n", pd);
   return 0;
}

すごく簡単にするために
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へのポインタを別の型のポインタに代入する局面で明示的なキャストを必須としているのは、このような危険を避けるためです。

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

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

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 4

checkベストアンサー

+3

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

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

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

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

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/01/20 19:19

    mit0223さんと同じく、やはり避けるべきなんですね!
    ん~~~

    この辺りは難しいですね・・・

    キャンセル

  • 2017/01/20 19:22

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

    キャンセル

+2

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

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

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

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

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

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

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/01/20 19:12

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

    キャンセル

  • 2017/01/20 19:17

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

    キャンセル

  • 2017/01/20 19:21

    分かりました。

    キャンセル

  • 2017/01/20 19:30

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

    キャンセル

  • 2017/01/20 19:33 編集

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

    char* pc = &x;こいつはwarningがでています。

    キャンセル

  • 2017/01/20 19:35

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

    キャンセル

0

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

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

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

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

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/07/21 12:57

    ありがとうございます。

    キャンセル

0

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

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

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

同じタグがついた質問を見る

  • C

    4382questions

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

  • C++

    4304questions

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