• ベストアンサー

暗黙的型変換

C の文法書を読んでいると、 汎整数型拡張: int より小さな汎整数型が式中に現れる場合は、暗黙的に int 型に変換される。 算術変換: 二項演算子で二つのオペランドの型が違う場合は、演算前により大きな方の型に暗黙的に変換される。 とあります。 例えば int 型 = unsigned short 型 - unsigned char 型; はどのように暗黙的な型変換が行われるのでしょう。 int 型 = (int)unsigned short 型 - (int)unsigned char 型; でしょうか。あるいは、 int 型 = (int) ( unsigned short 型 - (unsigned short)unsigned char 型); でしょうか。

  • tanuk
  • お礼率100% (26/26)

質問者が選んだベストアンサー

  • ベストアンサー
  • liar_adan
  • ベストアンサー率48% (730/1515)
回答No.6

>ただ私の読んでいる本では、算術型変換の説明に > unsigned char と char の演算では unsigned char に変換される >という説明まで載っているので、 その記述はおそらくうっかりミスだと思います。 書名を教えてください。 >int が 8 ビットの場合まで想定して書かれているのでしょうかね。 int型は規格で、-32767~+32767の範囲を表現できることが義務づけられているので、 最低16ビットです。 (一方で、char型が16ビット以上という環境は有り得るそうですが) 正確な用語では、 「汎整数拡張」は 「通常の算術型変換」の一部ということです。 つまり、違う型の混じった計算は (1)char, shortなどに対して、まず汎整数拡張が行われてint型に変換される。 (2)次に、算術型変換(サイズが大きい方の型に合わせる)が行われる。 (広い意味では(1)(2)を含めて算術型変換と言う) となります。最初に考えていたこととたぶん一緒だと思います。

tanuk
質問者

お礼

再度回答ありがとうございます。よく分かりました。 > その記述はおそらくうっかりミスだと思います。 書名を教えてください。 特殊な本で、一般の人は入手できないので書名は出さないことにします。

その他の回答 (5)

  • MetalKing
  • ベストアンサー率57% (15/26)
回答No.5

整数演算の場合、以下のようなルールがあります 一方のオペランドが unsigned long 型でれば、もう一方のオペランドが unsigned long 型に変換されます。 上の条件を満たさないとき、一方のオペランドが long 型、もう一方のオペランドが unsigned int 型であれば、両方のオペランドが unsigned long 型に変換されます。  上の 2つの条件を満たさないとき、一方のオペランドが long 型であれば、もう一方のオペランドが long 型に変換されます。  上の 3 つの条件を満たさないとき、一方のオペランドが unsigned int 型であれば、もう一方のオペランドが unsigned int 型に変換されます。  上の条件をすべて満たさないときは、両方のオペランドが int 型に変換されます。 ∴ 今回の事例では 全て int に拡張されてから演算されます。

tanuk
質問者

お礼

回答ありがとうございます。

  • liar_adan
  • ベストアンサー率48% (730/1515)
回答No.4

汎整数拡張が行われるので、 >int 型 = (int)unsigned short 型 - (int)unsigned char 型; が正しいです。 実験してみます。足し算の方がわかりやすいと思うので 足し算にしました。 ------------- #include <stdio.h> int main(void) { unsigned short a = 65530; unsigned char b = 255; int c; unsigned short d; c = a + b; d = a + b; printf("c = %d, d = %d\n", c, d); return 0; } ------------- これを実行すると、 >c = 65785, d = 249 となります。 もし、 >int 型 = (int) ( unsigned short 型 - (unsigned short)unsigned char 型); のようにunsigned shortのまま計算されるとすれば、 二つの値は同じになるはずです。 算術型変換は、汎整数拡張の後に行われます。 (intより大きな型の場合に行われます)

tanuk
質問者

お礼

回答ありがとうございます。 > 算術型変換は、汎整数拡張の後に行われます。 (intより大きな型の場合に行われます) というルールがあるのなら話は明確ですね。ただ私の読んでいる本では、算術型変換の説明に unsigned char と char の演算では unsigned char に変換されるという説明まで載っているので、「intより大きな型の場合に行われます」というのがちょっと理解できないのですが。 int が 8 ビットの場合まで想定して書かれているのでしょうかね。

  • sha-girl
  • ベストアンサー率52% (430/816)
回答No.3

基本的にはサイズの大きい型にキャストされます。 この場合 int a; unsigned short b; unsigned char c; でa=b-cとするなら 最初にb - cの計算が行われるわけですが まずb - (unsigned short)c でこの結果をaにいれるわけですから a = (int)(b - (unsigned short)c); つまり int 型 = (int) ( unsigned short 型 - (unsigned short)unsigned char 型); ですね。 やはり明示的にキャストしや方が分かりやすいと思います。

tanuk
質問者

お礼

回答ありがとうございます。 そうですか、そうすると「汎整数型拡張」というルールは使われないということでしょうか。

  • nitscape
  • ベストアンサー率30% (275/909)
回答No.2

#1です。これも自信ないですが、 long=(long)short - long ということではないでしょうか? 代入先がintなら int=(int)((long)short - long) という風になるのかもしれません。私はこの手の型が違う計算は明示的にキャストして使っていることもありまったく自信がないです。

tanuk
質問者

お礼

回答ありがとうございます。

  • nitscape
  • ベストアンサー率30% (275/909)
回答No.1

自信はまったくないですが、アセンブラで考えるとeaxなどのレジスタに値を代入してからsubなどで演算しますよね。ということは。。。 int 型 = (int)unsigned short 型 - (int)unsigned char 型; となるのではないでしょうか?

tanuk
質問者

お礼

回答ありがとうございます。 確かにそのようにも思えるのですが、「算術変換」はどのような場合には適用されるのでしょうか。

関連するQ&A

  • 汎整数拡張の通常の算術型変換

    「汎整数拡張」の「通常の算術型変換」に <一方のオペランドが型unsigned long intをもつ場合、他方のオペランドをunsigned long intに型変換する。> この下に「そうでない場合」が、一方のオペランドが型long intをもつ場合が二つ続きます。 <一方のオペランドが型unsigned intをもつ場合、他方のオペランドをunsigned intに型変換する。> <>2つの例はlong型やint型よりもunsigned型の上位に位置づけています。 例として   if(-1<1u)は偽になります。 何ゆえにunsigned型の上位性をしているのでしょうか。宜しく願います。

  • シフト演算の結果の型

    シフト演算の結果の型は、左オペランドの型ということを聞きました。 この左オペランドの型というのは算術型変換をしてからのか、する前の型なのかどちらなのでしょうか? 例えば int a = -2; unsigned int b = 1; a >> b このときの結果の型は何になるのでしょうか? 算術型変換が起きる前のintになるのか? それとも算術型変換が起きるた後のunsigned intになるのか? 例文としてはおかしい点もあるかもしれませんが よろしくお願いします。

  • unsigned int型と int型の型変換の上位性

    if(-10<1u)の条件判定はunsigned型で評価され偽となります。 int型 unsigned int型とも32ビットで考えたとき、 1u = 0x00000001 -10 = 0xfffffff6で10進法では4294967286になります。 条件判定をunsigned型で考えれば確かに-10<1uは偽になり int型で考えれば-10<1uは真になります。 「通常の算術変換」によれば、「一方のオペランドがunsigned int型をもつ時、他のオペランドをunsigned int型に型変換するとあります。」 よって、if(-10<1u)の条件判定はunsigned型で評価され偽となりますが、 「一方のオペランドがint型をもつ時、他のオペランドをint型に型変換する。」では何故いけないのでしょうか? 宜しく願います。

  • C言語の型変換について

    short int 型をunsigned char型に変換する方法をおしえてください

  • 文字列をint型にキャスト

    文字列をunsigned int型キャストし,それをある演算をして 正の整数に変換したいのですがどうすればいいですか? int ca(char *s) { unsigned int h; int key; h = (unsigned int)s; //文字列を演算し 0~254 の整数にする// key = h % 254; return key; } int main() { char moji[32]; moji = "moji"; unsigned int c; c = ca(moji); }

  • 算術型変換について

    c言語で算術型変換がどのように行われているかの質問です。 例えばintが16bitでlongが32bitの環境であるとします。 そして以下のようなプログラムがあるとします。 unsigned long x = 100; signed int y = 1; unsigned int z = 5; long test = x + (y - z); 1、 このときまずy-zについて算術型変換が起きてyとzがunsigned intとなり、 y-z=65532となる。 そしてx/(y-z)について算術型変換が起き、xと(y-z)がunsigned longとり、 x+(y-z)=65632となるのでしょうか? 2、 もしくはx+(y-z)のすべてに算術型変換を起こしてから計算を行うのでしょうか? y-zの結果の型をunsigned longとして計算し、y-z=4294967292になるのでしょうか? 文章がうまくまとめられていないのですが、どちらになるのでしょうか?

  • 暗黙の型変換をやめたい

    ASP.NET(C#2.0)からSQLServer2008R2のストアドプロシージャをコールする際、暗黙の型変換を使うとパフォーマンスが落ちるらしいので、全て明示的な型変換に修正したいと思っています。 MySQLをselectした値をリーダー(reader)に格納し、SQLServerにストアドコール時にパラメータ指定してinsertするのですが、何が暗黙的で何が明示的なのかわかりません。 下記は引数1にパラメータ、引数2にDBType(省略可)、引数3に値を指定しています。 [暗黙的かと思われるパラメータの渡し方] AddParameter("@パラメータ1", reader["値1"]); //char(2) AddParameter("@パラメータ2", DbType.string, reader["値2"].ToString()); //nvarchar(20) [明示的かと思われるパラメータの渡し方] AddParameter("@パラメータ3", DbType.DateTime, Convert.ToDateTime(reader["値3"])); //datetime AddParameter("@パラメータ4", DbType.Currency, (Convert.ToDecimal(reader["値4"])) * 100); //money 暗黙の型変換とは、引数3の型を指定しない場合に起こるという認識で合っていますでしょうか?

  • GCCで暗黙の型変換の警告を出したい

    情報が失われてしまうような代入について警告を出したいのですが、 どういったオプションを用いればよいでしょうか? コンパイラはGCCの3.x系か4.x系でお願いします。 以下のようなソースで型変換に関する警告がほしいんです。 --- test.c --- #include <stdio.h> int main(void) {   int a = 66000;   short b;   b = a; // <- 暗黙の型変換   printf("%d\n", b);   return 0; } 実行結果 $ ./test 464 以下のオプションを試しましたが、上記のソースでは 何の警告も出ませんでした。 -W -Wall -Wconversion -Wimplicit ご存知の方いらっしゃいましたら、どうかお助け下さい。

  • C++ basic_ostreamの拡張

    UTF-16文字列を扱うためのostreamを用意したいのですが、wcoutの代わりに、unsigned shortを用いたostreamを使いたいと思いました。 そこで、basic_ostreamのクラスのunsigned short型のインスタンスを作ったのですが、以下のエラーが出てしまってコンパイルが出来ませんでした。 「error C2296: '<<' : 無効です。左オペランドには型 'u16ostream (__cde cl *)(void)' が指定されています。」 「error C2297: '<<' : 無効です。右オペランドには型 'u16char *' が指定 されています。」 コンパイラはVC++2008です。 それとついでですが、通常通りwcoutを使う時みたいに、localeを設定する必要はあるのでしょうか? 回答、よろしくお願いします。 /* 以下ソースコード */ #include <iostream> typedef unsigned short u16char; typedef basic_ostream<u16char> u16ostream; int main() { u16ostream ucout(); u16char* str = (u16char*)(L"ああ"); ucout << str << '\n'; return 0; }

  • C#で型変換がうまくいきません。

    C#で型変換がうまくいきません。 short r; byte[] b = new byte[] {1,2,3}; r = (short)b[1] * (short)256; というコードを書くと、 型 'int' を 'short' に暗黙的に変換できません。明示的な変換が存在します。(cast が不足していないかどうかを確認してください) と出てしまいます。キャストしているのに何がいけないのか全くわかりません。 どうぞ宜しくお願いいたします。

専門家に質問してみよう