暗黙の型変換

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

暗黙の型変換

#1

投稿記事 by 研修生 » 16年前

暗黙の型変換についてご質問です。私の参考書ではライブラリ関数strchrの中身はこのようになっていました。
char *strchr(const char* s, intc)
{
   c=(char)c;
   while(*s!=c){
     if(*s=='\0'){
         return NULL;
     }
     s++;
   }
   return (char *)s;
}

int main()
{
  char str[50];
  char temp
  int ch;
 scanf("%s",str);
  scanf("%s",temp)
  ch=temp[0];
  //printfの処理
  return 0;
}
最初の所のキャストを行なっていますが暗黙の型変換によってこれは
c=(int)(char)c; となりこのキャストは無意味になっています。
これを意味のあるものにするにはどのように変更すればいいでしょうか?

御津凪

Re:暗黙の型変換

#2

投稿記事 by 御津凪 » 16年前

打ち間違い等はさておき、
> c=(int)(char)c;
少なくとも、 c の値を char 型のサイズに丸めて int 型としているという意味にはなります。

char 型が 8bit 表現であれば、
char 型 の範囲内に丸められ、 8bit 表現値の範囲内にあることが保障できます。

これは、
c &= 0xff;
と動作結果は全く同じ(はず)です。

研修生

Re:暗黙の型変換

#3

投稿記事 by 研修生 » 16年前

意味は理解できましたが、解決策がほしいです。

御津凪

Re:暗黙の型変換

#4

投稿記事 by 御津凪 » 16年前

> 意味は理解できましたが、解決策がほしいです。

この解決策というのは、

> これを意味のあるものにするにはどのように変更すればいいでしょうか?

ということでしょうか?
そういうことであれば、上記に記載した通り、
"c=(char)c;" は意味のある(char 型のサイズに丸める)処理です。
この時点で意味があるのでそのままで OK です。

もし回答の意味が違う(ずれている)のであればその詳細をお願いします。


ちなみに引数を int から char にすると、 "c=(char)c;" の部分は不要になり(最適化されて無視され)ます。

また、C標準ライブラリ関数の引数(及び文字を返す関数の戻り値)に文字の型が char 型でないのは、
処理系によって char 型のサイズが違うことがあるため関数呼び出しの動作が変わってしまうのを防ぐためです。
(仕様を見ていないので不明ですが…)

研修生

Re:暗黙の型変換

#5

投稿記事 by 研修生 » 16年前

うーん、そのキャストは意味がないと先輩に言われて質問したんですが。
c=(char)cは左辺がintなので折角キャストしても暗黙のキャストでintに戻ってしまう。
つまりc=(int)(char)cになってしまう という指摘を受けました。
この指摘は間違っているのでしょうか?
※VisualC++6.0が開発環境ですのでcharのサイズは1でした

御津凪

Re:暗黙の型変換

#6

投稿記事 by 御津凪 » 16年前

> c=(char)cは左辺がintなので折角キャストしても暗黙のキャストでintに戻ってしまう。

「型」としての説明では正しいですが、「変数の値」としての話なら間違いです。

一度、下記のプログラムを実行してみてください。
#include <stdio.h>

void putval_int_cast_char( int c ){
    printf("[cast befor: %5d, ", c); // キャスト処理前の c の値
    c = (char)c;
    printf("cast after: %5d]\n", c); // キャスト処理後の c の値
}

int main( void ){
    printf("Char:\n");
    putval_int_cast_char('a');
    putval_int_cast_char('A');
    putval_int_cast_char('\0');
    printf("Int:\n");
    putval_int_cast_char(-32);
    putval_int_cast_char(132);
    putval_int_cast_char(256);
    putval_int_cast_char(-256);
    putval_int_cast_char(1600);
    putval_int_cast_char(-1600);

    return -1;
}
この処理を、こちらで mingw32 でデフォルト設定でコンパイル・実行した出力結果が下記になります。
Char:
[cast befor:    97, cast after:    97]
[cast befor:    65, cast after:    65]
[cast befor:     0, cast after:     0]
Int:
[cast befor:   -32, cast after:   -32]
[cast befor:   132, cast after:  -124]
[cast befor:   256, cast after:     0]
[cast befor:  -256, cast after:     0]
[cast befor:  1600, cast after:    64]
[cast befor: -1600, cast after:   -64]
このようにキャスト前と後では値が変化しています。
これを踏まえてもう一度聞いてみてはどうでしょうか?
(もしかしたら先輩さんの説明が足りなかったのかもしれません)

研修生

Re:暗黙の型変換

#7

投稿記事 by 研修生 » 16年前

激しく無知で恐縮なのですが値が変化していればどうなるのでしょう?
優先順位がchar<intなので暗黙の型変換が行なわれるという認識だったのですが、優先順位が
変わるのでしょうか?

御津凪

Re:暗黙の型変換

#8

投稿記事 by 御津凪 » 16年前

> 値が変化していればどうなるのでしょう?

たとえば strchr 関数の引数 c に 1600 を渡したとします。
c = (char)c; の処理により値が変化し、 64 という値になります。
64 はアスキーコードで '@' を表すため、 '@' が渡されたものとして、以降の処理を行います。


暗黙の型変換は、コンパイラが行っても問題ないと判断したときに行います。
(できなかったらエラーを出す)
警告レベルを最大にすると、値が変化する可能性のある暗黙の型変換(大きい型から小さい型への場合)
は全て警告として表示されます。
(逆は値が変化することがないため警告は出ません)

基本、暗黙の型変換には優先順位がありません(代入先の型に合わせるため)。
ただし、明示的な型変換があればそちらを優先し、その後、代入先の型と合わなければ暗黙の型変換が試みられます。
(明示的型変換 > 暗黙的型変換)

明示的型変換どうしの場合は、右から順に行われます。
c = (int)(char)c;
この例だと、 char 型にキャストしてから int 型にキャストします。

たかぎ

Re:暗黙の型変換

#9

投稿記事 by たかぎ » 16年前

char型が符号付きか符号無しかは処理系定義です。Visual C++に限った場合でも、コンパイルオプションに依存します。
そして、符号付き整数型に表現範囲を超えた値を型変換しようとした場合、処理系定義の値になるか、処理系定義のシグナルが発生します。Visual C++に限れば期待通りに動作しますが、そうでなければ誤動作の可能性があります。つまり移植性がありません。
移植性に配慮して書き直すと、
char *strchr(const char* s, intc)
{
   const unsigned char *ss = (const unsigned char*)s;

   c=(unsigned char)c;
   while(*ss!=c){
     if(*ss=='\0'){
         return NULL;
     }
     ss++;
   }
   return (char *)ss;
}
としなければなりません。

研修生

Re:暗黙の型変換

#10

投稿記事 by 研修生 » 16年前

ちょっと考えてみます。ありがとうございました。

閉鎖

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