15 printf(" array a[]:%3d byte \n", sizeof(a));
16 return 0;
17 }
[motoki@x205a]$ gcc datatype-sizeof.c [motoki@x205a]$ ./a.out
char: 1 byte short: 2 byte int: 4 byte long: 4 byte unsigned: 4 byte float: 4 byte double: 8 byte long double: 12 byte array a[]: 40 byte [motoki@x205a]$
5.10 型変換とキャスト
{ケリー&ポール3.10節} 算術計算の際の自動型変換:
• 型の異なるデータ間で算術計算を行う際には、2つのデータの型を揃えたりするため に、内部では次の順に強制的に型変換が行われる。
1 char型やshort型のデータはint型に変換される。
2 データ型間の次の順序に従って、下位(i.e. 左)の方の型が上位の型に変換され る。(変換後の型が演算結果の型になる。)
int< unsigned < long <unsigned long
< float <double < long double
=⇒ char型同士の加算結果はcharではなくint型。
• 実数→整数 間の型変換が実際にどう行われるかについては計算機に依存する。 [切 捨て、切り上げ、四捨五入のいずれか。]
代入の際の自動型変換:
• 代入 変数等 = 式 において両辺の型が違えば、式の値は変数等の型に強制的に変換 される。
キャスト演算子:
• 明示的に型変換を行うことが出来る。
• 式の値をデータ型という型に変換したければ、次の様に書く。
( データ型 ) 式
• キャストは単項演算子。
146 5. 自習 基本的データ型
• 他の単項演算子(e.g.符号反転の-,++)と同じ優先順位、結合性(右から左)を持つ。
例 5.7 (キャスト演算の優先順位) (float) i+3 は ((float)i) + 3 と同等。
5.11 16 進定数と 8 進定数
{ケリー&ポール3.11節} 16進数:
• 0∼9, A∼F(各々10∼15の代わり)の16個の数字を用いて数を表したもの。
• 16進数字の列
hn−1hn−2· · ·h2h1h0
によって、
Pn−1
i=0 hi×16i
という数を表す。例えば、16進数A0F3C は次の10進数を表す。
|{z}10
A
×164+ 0×163+ 0×163+ 15
|{z}
F
×162+ 3×161+ 12
|{z}
C
×160
= 659260
• 非負整数 x を表す16進数を求めるには
hi = mod(⌊x/16i⌋,16) = (⌊x/16i⌋を16で割った余り)
を計算し、これらを並べればよい。例えば、x= 659260 の場合には次のように計算 する。
659260 16
41203 2575 160 10 0
余り12 余り 3 余り15 余り 0 余り10
A 0 F 3 C
659260を16で割っている
答 16
16 16 16
8進数: (16進数の場合と同様)
16進定数と8進定数: C言語においては、
• 0 0∼7の数字列 という形の字句は整数を8進表記したものと見なされる。
• 10∼15を表す16進数字としては、英大文字 A∼F と同様に英小文字 a∼f も許され、
0x 16進数字の列 または 0X 16進数字の列 という形の字句は整数を16進表 記したものと見なされる。
• 変換指定を %x または %#xとして書式付き出力(e.g.printf)を行えば、整数を16進 表記で出力できる。また、変換指定を%x として書式付き入力(e.g.scanf)を行えば、
16進表記の整数を入力できる。
5.11. 16進定数と8進定数 147
• 変換指定を %oまたは %#oとして書式付き出力(e.g.printf)を行えば、整数を8進表 記で出力できる。また、変換指定を %o として書式付き入力(e.g.scanf)を行えば、8 進表記の整数を入力できる。
• unsigned やlongの指定を行いたければ、10進の場合と同様、それぞれu(またはU)
やl(またはL) を定数の最後に付ける。
例 5.8 (16進定数,8進定数の扱い) 16進定数, 8進定数, %x変換, %#x変換, %o変換, %#o の使用例を次に示す。
[motoki@x205a]$ nl datatype-hexadecimal-const-Kelley.c 1 #include <stdio.h>
2 int main(void) 3 {
4 printf("%d %#x %#o\n", 19, 19, 19);
5 printf("%d %x %o\n", 19, 19, 19);
6 printf("%d %x %o\n", 0x1c, 0x1c, 0x1c);
7 printf("%d %x %o\n", 017, 017, 017);
8 printf("%d\n", 11 + 0x11 + 011);
9 printf("%d\n", 2097151);
10 printf("%d\n", 0x1FfFFf);
11 return 0;
12 }
[motoki@x205a]$ gcc datatype-hexadecimal-const-Kelley.c [motoki@x205a]$ ./a.out
19 0x13 023 19 13 23 28 1c 34 15 f 17 37 2097151 2097151
[motoki@x205a]$
演習問題
□演習 5.1 (C言語における文字の扱い) 次のCコードを実行するとどういう出力が得ら
れるか?
printf("(5)%d\n", 49);
printf("(6)%c\n", 49);
148 5. 自習 基本的データ型
□演習 5.2 (C言語における文字の扱い) 次のCコードを実行するとどういう出力が得ら
れるか?
char a[]={’c’, ’a’, ’t’, ’s’, ’\0’};
printf("(1)%c%c%c\n", a[0], a[1], a[2]);
printf("(2)%s\n", a+2);
printf("(3)%c%c%c\n", *a+1, *a+2, *a+3);
printf("(4)%3d%3d\n", a[0]-’a’, a[1]-’a’);
□演習 5.3 (C言語における文字の扱い) 次のCコードを実行するとどういう出力が得ら
れるか?
int a[4]={97,98,99,0};
printf("(2)%3d%3d%3d\n", a[0], a[1], a[2]);
printf("(3)%c%c%c\n", a[0], a[1], a[2]);
□演習 5.4 (<stdio.h>の中身) 2つの関数getcharとputcharが/usr/include/stdio.h の中でどのように定義されているか調べてみよ。
□演習 5.5 (Queenの勢力範囲) チェス盤の状況は8×8の 文字パターンで表すことができる。 Queenの駒の位置を 表す2つの非負整数x, y (右図参照)を読み込んで、
* Q y
1 2 3 4 5 6 7 x 0
1 2 3 4 5 6 7
0
* * * * *
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
• Queenの居る場所は文字Q を、
• Queenの勢力範囲、すなわち
Queenと同じ行の場所 (0, y),(1, y), ...,(7, y), Queenと同じ列の場所 (x,0),(x,1), ...,(x,7), 右上がりの対角線上の場所
...,(x−2, y−2),(x−1, y−1), (x+ 1, y+ 1),(x+ 2, y+ 2), ..., 右下がりの対角線上の場所
...,(x−2, y+ 2),(x−1, y+ 1), (x+ 1, y−1),(x+ 2, y−2), ..., には星印 * を、
• その他の場所にはハイフン - を
入れた文字パターンを出力するプログラムを作成せよ。 このプログラムは、例えばx = 2, y = 3 に対しては次の様な文字パターンを出力することになる。
--*---*-
--*--*-- *-*-*---
-***----**Q*****
-***---- *-*-*---
--*--*--□演習 5.6 (10進→2進変換) 2147483647以下の非負整数を入力として受け取り、その 値を2進数として表示するCプログラムを作成せよ。
5.11. 16進定数と8進定数 149
□演習 5.7 (<limits.h>の中身) /usr/include/limits.h の中身を覗いて実習室の計算 機で扱える最大整数値がどうなっているか調べてみて下さい。
□演習 5.8 (32bitでの整数表現) 長さが32の 0 と 1 の数字列 b31b30b29· · ·b4b3b2b1b0
を入力して、
1 このビット列を unsigned型(すなわちunsigned int型)データと見た時に表す(非負) 整数値P31i=0bi×2i、 および
2 このビット列をint型(すなわちsigned int型)データと見た時に表す整数値−b31×231+
P30
i=0bi×2i
を出力するCプログラムを作成せよ。
□演習 5.9 (右シフトの際の補充ビット) 実習室の計算機において右シフトの際の補充ビ
ットがどうなるか、調べてみて下さい。
□演習 5.10 (シフト演算子の第2オペランドが負なら ...) シフト演算子の第2オペラン ドが負の場合どういう演算結果になるか調べよ。
□演習 5.11 (<float.h>の中身) /usr/include/float.h の中身を覗いて実習室の計算 機で扱える最大の浮動小数点数がどうなっているか調べてみて下さい。
□演習 5.12 (IEEE規格754による実数表現) 長さが32の 0 と 1の列 se7e6· · ·e1e0d1d2d3· · ·d23
を入力して、このビット列の表す実数値(実数表現の仕方はIEEE規格754に従うものと 仮定する)
(−1)s×(1 +M)×2E if −127< E <128 (−1)s×M ×2E+1 if E =−127
Inf(無限大) if E = 128, M = 0 NaN(非数,Not a Number) if E = 128, M 6= 0 ここで、M =P23i=1di×2−i, E =P7i=0ei×2i−127 を出力するCプログラムを作成せよ。
'
&
$
% Hint:
2P7i=0ei×2i−127
= 2(e7−1)×27+P6i=0ei×2i+1
= ((· · ·(((1/2(1−e7))2×2e6)2×2e5)2· · ·)2×2e1)2×2e0 ×2
□演習 5.13 (データの内部表現)
(1) (半角)文字の並び38はJIS 8ビット符号体系ではどんなビット列で表されるか? 16
進表記で答えよ。
(2) 10進整数の38は8ビットの整数データとしてどの様に表されるか? 2進表記で答
えよ。
(3) 10進整数の−38は2の補数表示により8ビットの整数データとしてどの様に表され
るか? 2進表記で答えよ。
150 5. 自習 基本的データ型
(4) 10進で表された実数値 38.0はIEEE規格754の単精度実数としてどの様に表される
か? 2進表記で答えよ。
□演習 5.14 (データの内部表現)
(1) ビット列0110 0100 0100 1010 を16進表記で表せ。
(2) ビット列0110 0100 0100 1010 がJIS8ビット符号体系の文字列を表しているとする
と、何の文字列を表しているか?
(3) ビット列0110 0100 0100 1010 が符号付き整数を表しているとすると、 何の整数を
表しているか?
(4) ビット列 0110 0100 0100 1010 が符号付き整数を表していると見て、その正負の符
号を反転するとどんなビット列になるか? 但し、ここでは、負数は2の補数で表 すとする。
□演習 5.15 (どちらの計算式が良いか) double型変数x に対して式
q|x|+ 1−q|x| (= √ 1
|x|+1+√
|x|)
の値を計算するのに、次のどちらの算術式が精度の点で好ましいか?その理由も述べよ。
(a) sqrt(fabs(x)+1)-sqrt(fabs(x)) (b) 1/(sqrt(fabs(x)+1)+sqrt(fabs(x)))
□演習 5.16 (累算の順序) loge2 =
X∞
k=1
(−1)k+1
k = 0.69314718· · ·の近似式 a= 1− 1
2 +1 3 −1
4 +· · ·+ 1
99999 − 1 100000
の値を次の4通りの順序で計算して、それらの結果を真値 a = 0.693142180· · · と比較し てみよ。 また、それぞれの計算においてどの様な誤差/現象が発生するかを考えてみる ことによって、これらの計算順序のどれが良いか検討せよ。
(1) 1− 1 2+ 1
3− 1
4+· · ·+ 1
99999 − 1
100000 (定義通りに累算)
(2) 1− 1 2
+
1 3− 1
4
+· · ·+
1
99999 − 1 100000
2項ずつ組にして 大きい順に累算
(3) − 1
100000+ 1
99999 − · · · −1 4 +1
3 −1
2 + 1 (定義の逆順に累算)
(4) 1
100000×99999+· · ·+ 1
4×3 + 1 2×1
式を変形して 小さい順に累算
□演習 5.17 (10進→16進変換) 2147483647以下の非負整数を入力として受け取り、そ の値を16進数として表示するCプログラムを作成せよ。
151
6 実習 GDB デバッガ
• 実行時のエラーについて,
• 自習 coreファイルを用いたデバッグ,
• GDBを用いて実行追跡する例,
• GDBデバッガの使い方,
• 中断点を指定して実行追跡する例,
• GDBを使って変数の内部状態を調べる例,
• 自習 実行中のプログラムの追跡,
文法的に正しいプログラムの虫取り(debug; i.e. 虫,bug,すなわち 誤りを取り除くこと) のために、実習室の計算機にはGDB というデバッガが備わっています。GDBを用いれ ば、プログラムが異常終了した際に生成される(ことがある)coreファイルを使って異常 の起こった場所を突き止めたり、C(やFortran, Pascalなどの)プログラムの実行を追跡し て実行途中の変数値を調べたり、できます。
参考文献:
• R.M.Stallman&R.H.Pesch「GDB入門」(1999年,アスキー出版局, 1900円+税)
• 小山祐司&斉藤靖&佐々木浩&中込知之「UNIX入門 フリーソフトウェアによる最新UNIX 環境」(1996年, トッパン)