問題① 次の変数 n1~n8 の型はそれぞれ何が適切ですか?(あえて大きい型を使わないとして)
signed char sc = -10;
unsigned short us = 10;
???? n1 = 10L;
???? n2 = 10LL;
???? n3 = 10LU;
???? n4 = 10 + n1;
???? n5 = n2 + n3;
???? n6 = sc * 2;
???? n7 = sc * us;
???? n8 = sc + 100LL / 2U;
n1 の初期化子は 10L
です。整数定数に
Lサフィックスを付加した場合、long int になります(表現できない値なら
long long int や拡張整数型になるかもしれないが、10
は表現できる)。したがって、n1 の型は long int
です。
n2 では 10LL
を指定しています。整数定数に
LLサフィックスを付加した場合、long long int
になります(表現できない値なら拡張整数型になるかもしれないが、10
は表現できる)。したがって、n2 の型は long long
int です。
n3 では 10LU
を指定しています。LU
は、Lサフィックスと
Uサフィックスを両方指定したものです。Uサフィックスは符号無し整数型にすることを表しているので、n3 の型は unsigned long int です。
n4 では、10 + n1
を指定しています。10
は
int、n1 は long int でした。したがってこれは、int と long int
で計算を行っています。オペランドが2つある演算子で互いの型が異なる場合、通常の算術変換が適用されます。「両方とも
signed、あるいは両方とも unsigned
である場合、ランクが低い側が、ランクが高い側の型に変換される」の部分が適用されるので、long
int に合わせられます。したがって、4 は long int
です。
n5 では、n2 + n3
を指定しています。n2 は long long
int、n3 は unsigned long int
です。さきほどと同様に一方の型に合わせる変換が起こります。long long int
が 64ビット、unsigned long int が 32ビットの処理系であれば、「signed
の側の型が、unsigned
の側の型で表現できるすべての値を表現できるのなら、unsigned の側が signed
の型に変換される」に該当するので、n5 は long long
int になります。long long int と unsigned long int がともに
64ビットの処理系であれば、「両方とも、signed の側の型に対応する unsigned
な型に変換される」に該当するので、n5 は unsigned long
long int になります。
n6 では、sc * 2
を指定しています。sc は signed
char、2
は int です。signed char は int
よりもランクが低いため、まず整数拡張が行われ、int
に変換されます。そのため、sc * 2
は int
同士での演算になり、その結果もまた int です。したがって、n6 は int です。
n7 では、sc * us
を指定しています。sc は signed char、us
は unsigned short です。さきほどと同様、それぞれに整数拡張が行われ、sc
は int になります。unsigned short からの整数拡張は、unsigned short
で表現できる値のすべてが int でも表現できるなら
int、表現できない値があるのなら unsigned int
になります。したがって、unsigned short が 16ビット、int が
32ビットの処理系ならば int になります。いずれも
16ビットであるような処理系では unsigned int
になるでしょう。したがって、sc * us
は int と int
あるいは、int と unsigned int の乗算になります。前者なら n7 は int、後者なら「unsigned の側のランクが signed
の側のランク以上の場合、signed の側が unsigned
の側の型に変換される」が適用されるので、n7 は unsigned
int になります。
n8 では、sc + 100LL / 2U
を指定しています。sc は signed
char、100LL
は long long int、2U
は unsigned
int です。まず 100LL / 2U
が計算されます。long long int が
64ビット、unsigned int が 32ビットとすると、「signed
の側の型が、unsigned
の側の型で表現できるすべての値を表現できるのなら、unsigned の側が signed
の型に変換される」が適用されて、long long int
に合わせられます。sc
は整数拡張されて int になり、int と
long long int の加算を行うことになり、「両方とも
signed、あるいは両方とも unsigned
である場合、ランクが低い側が、ランクが高い側の型に変換される」が適用されるので、n8 は long long int です。もし、100LL / 2U
のとき、long long int と unsigned int が
64ビットであったとすれば、「両方とも、signed の側の型に対応する unsigned
な型に変換される」が適用され、両方とも unsigned long long int
に変換されます。そうなると、sc
との加算は int と unsigned
long long int の演算になるので、「unsigned の側のランクが signed
の側のランク以上の場合、signed の側が unsigned
の側の型に変換される」が適用され、n8 は unsigned long
long int になります。
問題② char型が符号付きか、符号無しかを判定するプログラムを作成してください。
方法はいくつかありえるかもしれませんが、CHAR_MIN が負数かどうかを調べるのが簡単でしょう。
#include <limits.h>
#include <stdio.h>
int main(void)
{
if (CHAR_MIN < 0) {
("signed.");
puts}
else{
("unsigned.");
puts}
}
実行結果:
signed.
問題③ 次のプログラム片を見てください。
signed char c1 = 120;
signed char c2 = 60;
signed char c3 = -100;
signed char result = c1 + c2 + c3;
signed char型で表現できる最大値は 127 であり、c1 + c2
の段階で溢れ出してしまうように思えます。実際には、最終的な result の値は
80
となり正しく計算できます。問題が起こらない理由を説明してください。
signed char型どうしの計算は、整数拡張によって
int型に拡張されます。したがって、120 + 60 + (-100)
という計算は int型で行われます。int型の大きさは少なくとも
16ビットはあるので、この程度の大きさの計算では溢れません。
計算結果の 80 は、signed char型の変数result へ代入する際に切り詰められます。しかし、80 であれば signed char型でも表現できるので、ここでも何も問題は起こりません。
return 0;
を削除(C言語編全体でのコードの統一)第20章から整数型に関係する内容を移動してくる形で、新規作成。
Programming Place Plus のトップページへ
はてなブックマーク に保存 | Pocket に保存 | Facebook でシェア |
X で ポスト/フォロー | LINE で送る | noteで書く |
RSS | 管理者情報 | プライバシーポリシー |