A.変数

 Copyright(C) 13May2004 coskx
Copyright(C) 13Jan2003
coskx

変数についての解説です。以下の項目で出来ています。
1.初めての変数の型
2.整数型変数と内部表現
3.実数型変数と内部表現
4.文字コード(JISローマ字コード)
APPENDIX 1 整数型変数の内部表現
APPENDIX 2 文字コードに関する補足
APPENDIX 3 日本語文字コード
APPENDIX 4 n進法
APPENDIX 5 2の補数表示とlong int 
APPENDIX 6 2の補数表示とshort int  



A.1 初めての変数の型

はじめて出てくる変数はint型とdouble型であろう。より正確な説明はA.2で見ることにして,最初に出会う変数の型としてint型とdouble型を覚えよう。

変数の型

宣言の方法 使い方

特徴

int

int tokyo,osaka;
int x,y,z;

x=1;
y=2;
z=x+y;
printf("%d %d\n",x,y);
printf("%x %x\n",x,y);
scanf("%d",&tokyo);
扱える値の範囲は-2147483648から2147483647で,答えがこの範囲を超えるような演算を行なうと,正しい値が求められない。

int型同士の割り算を行なうと少数点以下は切り捨てられる。

int型同士では,x%yの演算でxをyで割った時のあまりを求める演算が定義されている

double

double x1,x2;
double pp,qq;

x1=2.0;
x2=100.0;
printf("pp=%f\n",pp);
printf("pp=%10.5f\n,pp);

扱える範囲は±1.7E308(±1.7×10308) であり、少なくとも 15 桁の精度がある。


double型変数を使用するときの注意

double型変数の内部表現は近似値であるため,0.1を10回たし合わせても1にならない。

#include <stdio.h>
int main()
{
    double x=0.1;
    int i;
    double y=0.0;
    for (i=0;i<10;i++) y+=x;
    printf("%.30f\n",1.0-y);
    return 0;
}
/* 実行結果
0.000000000000000111022302462516
*/

ということは,次のプログラムは無限ループとなる
#include <stdio.h>
int main()
{
    double x=0.1;
    double y=-1.0;
    while (y!=0.0) {
        printf("%.30f\n",y);
        y+=x;
    }
    return 0;
}

double型変数がある値に等しくなるという条件を用いてはならない

double型変数とint型変数のデータ交換

double x=10.5;
int y;
のとき

y=x;
によって,y=10になる。

int x=10;
double y;
のとき

y=x;
によって,y=10.0になる。


A.2 整数型変数と内部表現


整数を格納することに出来る変数の内部表現について次の表にまとめる

変数の型 内部表現のバイト数(ビット数) 値の範囲

char
または
signed char

1バイト(8ビット) -128から127
文字コードを格納するのに使われる場合が多い
unsigned char 1バイト(8ビット) 0から255
文字コード,測定データを格納するのに使われる場合が多い

short int
または
short
signed short int
signed short

2バイト(16ビット) -32768から32767
unsigned short int
または
unsigned short
2バイト(16ビット) 0から65535

long int
または
long
signed long int
signed long

4バイト(32ビット) -2147483648から2147483647
unsigned long int
または
unsigned long
4バイト(32ビット) 0から4294967295

int型というのはCPUにとって最も都合がよいビットサイズを取ってコンパイラを作ってよいことになっている。そこでCPUに依存して,次のようにコンパイラが解釈する場合が多い。

8ビットCPU,16ビットCPU(例えばマイコン,DOS-PCなど)において単にintと宣言されたらshort intを指す。
32ビットCPU(例えばwindowsPC,UNIXマシンなど)において単にintと宣言されたらlong intを指す。

(int 型は,そのマシンにおける整数の標準サイズを意味する。たとえば,16 ビットマシンでは,int 型は通常 16 ビットになる。32 ビット マシンでは,int 型は通常 32 ビットである。したがって,int 型はターゲット環境によって,short int 型か long int 型のどちらかになる。なお単にunsignedと宣言されたらunsigned intと宣言されたのと同じになる。)

なお,ANSIの規格では次のようにコンパイラを作ることになっている。
16bit ≦ short int ≦ int ≦ 32bit ≦ long int


整数型変数の内部表現

整数定数の内部表現
整数定数とは,
int x=123;
short int s=1234;
char c='A';
などの右辺のことである。これらはすべてint型として扱われる。32ビットCPUなら,32ビットで作られた「123」,「1234」,「'A'の文字コード0x41(65)」が不要な上位ビットを捨てて,それぞれ32ビットのx,16ビットのs,
8ビットのcへ代入される。

unsigned型使用上の注意
「unsigned int x;」 のもとで
「for (x=0; x<10; x++)」は有効なループとなるが,
「for (x=9; 0<=x; x--)」は永久ループとなる。(xは負にはならないため)


A.3 実数型変数と内部表現


変数の型

内部表現のバイト数
(ビット数)

値の範囲

float

4バイト(32ビット)

符号 1 ビット,8 ビットの 2 進数の指数 (バイアス分 127 を含む),23 ビットの仮数から成る。仮数は、1.0 と 2.0 の間の数値を表わす。仮数の最上位ビットは常に 1 になるので、このビットは数値に含まれない。

1.175494351 E - 38から3.402823466 E + 38
(1.175494351×10-38から3.402823466×1038を表す)
の正・負の値を表すことが出来る。

double

8バイト(64ビット)

符号 1 ビット,11 ビットの 2 進数の指数(バイアス分 1023 を含む),52 ビットの仮数から成る。仮数は、1.0 と 2.0 の間の数値を表わす。仮数の最上位ビットは常に 1 になるので、このビットは数値に含まれない。

2.2250738585072014 E - 308から1.7976931348623158 E + 308
(2.2250738585072014×10-308から1.7976931348623158×10308を表す)
の正・負の値を表すことが出来る。


A.4 文字コード(JISローマ字コード)

コンピュータは文字を変数にしまうことが出来ない。そこで,文字を値に変換してしまうことにしている。 例えば「A」は十進数の65,「B」は66にして変数にしまうことにしている。文字はこのように整数であるため,int型変数やchar型変数にしまうこ とができる。char型変数は1バイトでできているため,多くの文字を効率よくしまうことができる。char型変数は文字をしまうのによく使われる。
逆にchar型変数に十進数の50がしまわれていても,それの意味するところが,数値の50なのか文字の「P」なのかは,コンピュータは知ることが出来ない。プログラムを作成する人が判断し,使い方を決める。
この文字コード(JISローマ字コード)の一覧を次に示す。これらの文字は32~126の値で出来ているため7ビットの幅で全文字種が定義されている。

文字コード表(JISローマ字コード表)

文字 コード
十進
コード
十六進

SP

32

20

!

33

21

"

34

22

#

35

23

$

36

24

%

37

25

&

38

26

'

39

27

(

40

28

)

41

29

*

42

2A

+

43

2B

,

44

2C

-

45

2D

.

46

2E

/

47

2F

文字 コード
十進
コード
十六進

0

48

30

1

49

31

2

50

32

3

51

33

4

52

34

5

53

35

6

54

36

7

55

37

8

56

38

9

57

39

:

58

3A

;

59

3B

<

60

3C

=

61

3D

>

62

3E

?

63

3F

文字 コード
十進
コード
十六進

@

64

40

A

65

41

B

66

42

C

67

43

D

68

44

E

69

45

F

70

46

G

71

47

H

72

48

I

73

49

J

74

4A

K

75

4B

L

76

4C

M

77

4D

N

78

4E

O

79

4F

文字 コード
十進
コード
十六進

P

80

50

Q

81

51

R

82

52

S

83

53

T

84

54

U

85

55

V

86

56

W

87

57

X

88

58

Y

89

59

Z

90

5A

[

91

5B

\

92

5C

]

93

5D

^

94

5E

_

95

5F

文字 コード
十進
コード
十六進

`

96

60

a

97

61

b

98

62

c

99

63

d

100

64

e

101

65

f

102

66

g

103

67

h

104

68

i

105

69

j

106

6A

k

107

6B

l

108

6C

m

109

6D

n

110

6E

o

111

6F

文字 コード
十進
コード
十六進

p

112

70

q

113

71

r

114

72

s

115

73

t

116

74

u

117

75

v

118

76

w

119

77

x

120

78

y

121

79

z

122

7A

{

123

7B

|

124

7C

}

125

7D

~

126

7E

 

 

 

JISローマ字コード表のもとになったASCIIコード(American Standard Code for Information Interchange,ISO 646-1991)では文字コード92(5C)の表す文字は「\」ではなく「\」である。またJISローマ字コード(JIS X 0201-1976)では文字コード126(7E)の表す文字は「~」ではなく,(表現できないが「_」を上下反転させたオーバースコア)である。
文字コードに関する補足

20(16進数)以下で重要な制御コードには次のようなものがある

制御コード(16進数) C言語での表現

意味

07

'\a'

ベル

09

'\t'

タブ

0A

'\n'

改行

0D

'\r'

行先頭へ,リターン

1B

 

escape


 APPENDIX 1 整数型変数の内部表現


char型,unsigned char型

2進数ビットパターン 16進数表現 char型として
10進数として認識
(2の補数表現)
unsigned char型として
10進数として認識

00000000

00

0

0

00000001

01

1

1

00000010

02

2

2

:

:

:

:

01111110

7E

126

126

01111111

7F

127

127

10000000

80

-128

128

10000001

81

-127

129

10000010

82

-126

130

:

:

:

:

11111101

FD

-3

253

11111110

FE

-2

254

11111111

FF

-1

255


short int型,unsigned short int型

2進数ビットパターン 16進数表現 short int型として
10進数として認識
(2の補数表現)
unsigned short int型として
10進数として認識

0000000000000000

0000

0

0

0000000000000001

0001

1

1

0000000000000010

0002

2

2

:

:

:

:

0111111111111110

7FFE

32766

32766

0111111111111111

7FFF

32767

32767

1000000000000000

8000

-32768

32768

1000000000000001

8001

-32767

32769

1000000000000010

8002

-32766

37770

:

:

:

:

1111111111111101

FFFD

-3

65533

1111111111111110

FFFE

-2

65534

1111111111111111

FFFF

-1

65535


long int型,unsigned long int型

2進数ビットパターン 16進数表現 long int型として
10進数として認識
(2の補数表現)
unsigned long int型として
10進数として認識

00000000000000000000000000000000

000000

0

0

00000000000000000000000000000001

000001

1

1

00000000000000000000000000000010

000002

2

2

:

:

:

:

01111111111111111111111111111110

7FFFFE

2147483646

2147483646

01111111111111111111111111111111

7FFFFF

2147483647

2147483647

10000000000000000000000000000000

800000

-2147483648

2147483648

10000000000000000000000000000001

800001

-2147483647

2147483649

10000000000000000000000000000010

800002

-2147483646

2147483650

:

:

:

:

11111111111111111111111111111101

FFFFFD

-3

4294967293

11111111111111111111111111111110

FFFFFE

-2

4294967294

11111111111111111111111111111111

FFFFFF

-1

4294967295


 APPENDIX 2 文字コードに関する補足

C言語では
char c;
に対して
c=65;
c=0x41;
c='A';
はすべて同じ意味となる。0x41は16進法の41のことであり,'A'と書いたら65あるいは0x41と書いてあるのと同じである。
同様に
if (c==65) {
if (c==0x41) {
if (c=='A') {
は同じ意味を表す。
また
c=0x48;
printf("%d %x %c\n",c,c,c);
では「72 48 H」が表示される。

テストプログラム

#include <stdio.h>

int main()
{
    char c;
    c=0x48;
    printf("%d %x %c\n",c,c,c);
    return 0;
}
/****実行結果****
72 48 H
*****************/


 APPENDIX 3 日本語文字コード

日本語の文字は文字種が8ビットで表される範囲を超えるため16ビットで表されている。(Unicodeは16ビット~32ビット)
これまでの情報通信技術の発展の歴史に対応して,現在4種類のコード表があり,同じ漢字が4つの異なるコードを持っている。しかし1つの文書ファイル中で異なる文字コードが混在することはない。

(1)JISコード UNIXワークステーションで用いられている

あ 2422 い 2424 う 2426

(2)区点コード

あ 0402 い 0404 う 0406

(3)Shift-JISコード(SJIS) WindowsPC,Macintoshなどで用いられている

あ 82A0 い 82A2 う 82A4

(4)EUCコード UNIXワークステーションで用いられている

あ A4A2 い A4A4 う A4A6

以下にひらがな部分の各文字コード表を示す。
      JIS SJIS EUC  +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +A +B +C +D +E +F
04区 2420 829E A4A0    ぁ あ ぃ い ぅ う ぇ え ぉ お か が き ぎ く 
04区 2430 82AE A4B0 ぐ け げ こ ご さ ざ し じ す ず せ ぜ そ ぞ た 
04区 2440 82BE A4C0 だ ち ぢ っ つ づ て で と ど な に ぬ ね の は 
04区 2450 82CE A4D0 ば ぱ ひ び ぴ ふ ぶ ぷ へ べ ぺ ほ ぼ ぽ ま み 
04区 2460 82DE A4E0 む め も ゃ や ゅ ゆ ょ よ ら り る れ ろ ゎ わ 
04区 2470 82EE A4F0 ゐ ゑ を ん ・ ・ ・ ・ ・ ・ ・ ・ ・ ・ ・ ・ 

 APPENDIX 4 n進法

十進法100までの表
  0  1  2  3  4  5  6  7  8  9
 10 11 12 13 14 15 16 17 18 19
 20 21 22 23 24 25 26 27 28 29
 30 31 32 33 34 35 36 37 38 39
 40 41 42 43 44 45 46 47 48 49
 50 51 52 53 54 55 56 57 58 59
 60 61 62 63 64 65 66 67 68 69
 70 71 72 73 74 75 76 77 78 79
 80 81 82 83 84 85 86 87 88 89
 90 91 92 93 94 95 96 97 98 99
100

八進法100(十進数の64)までの表
  0  1  2  3  4  5  6  7
 10 11 12 13 14 15 16 17
 20 21 22 23 24 25 26 27
 30 31 32 33 34 35 36 37
 40 41 42 43 44 45 46 47
 50 51 52 53 54 55 56 57
 60 61 62 63 64 65 66 67
 70 71 72 73 74 75 76 77
100

五進法100(十進数の25)までの表
  0  1  2  3  4
 10 11 12 13 14
 20 21 22 23 24
 30 31 32 33 34
 40 41 42 43 44
100

三進法100(十進数の9)までの表
  0  1  2
 10 11 12
 20 21 22
100

二進法100(十進数の4)までの表
  0  1
 10 11
100

十六進法100(十進数の256)までの表
  0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F
 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F
 50 51 52 53 54 55 56 57 58 59 5A 5B 5C 5D 5E 5F
 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F
 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F
 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F
 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F
 A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF
 B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF
 C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF
 D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF
 E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF
 F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF
100

 APPENDIX 5 long int 型変数と unsigned long int 型変数

long int型変数とunsigned long int型変数の振る舞いを見るプログラム

1ずつ増加のプログラム
このプログラムからは,unsigned long int型変数とlong int型変数において
変数のbitパターンに区別がないことがわかる。
printfにおける書式で表示が異なっているだけである。
 

#include <stdio.h>

int main()
{
    long int xx;
    unsigned long int yy;
    int i;
    xx=-5;
    for (i=0;i<10;i++) {
        printf("xx=%12d %12u %08x\n",xx,xx,xx);
        xx++;
    }
    yy=4294967291;
    for (i=0;i<10;i++) {
        printf("yy=%12d %12u %08x\n",yy,yy,yy);
        yy++;
    }
    xx=2147483642;
    for (i=0;i<10;i++) {
        printf("xx=%12d %12u %08x\n",xx,xx,xx);
        xx++;
    }
    yy=2147483642;
    for (i=0;i<10;i++) {
        printf("yy=%12d %12u %08x\n",yy,yy,yy);
        yy++;
    }
    return 0;
}

 
実行結果  

xx=          -5   4294967291 fffffffb
xx=          -4   4294967292 fffffffc
xx=          -3   4294967293 fffffffd
xx=          -2   4294967294 fffffffe
xx=          -1   4294967295 ffffffff
xx=           0            0 00000000
xx=           1            1 00000001
xx=           2            2 00000002
xx=           3            3 00000003
xx=           4            4 00000004
yy=          -5   4294967291 fffffffb
yy=          -4   4294967292 fffffffc
yy=          -3   4294967293 fffffffd
yy=          -2   4294967294 fffffffe
yy=          -1   4294967295 ffffffff
yy=           0            0 00000000
yy=           1            1 00000001
yy=           2            2 00000002
yy=           3            3 00000003
yy=           4            4 00000004
xx=  2147483642   2147483642 7ffffffa
xx=  2147483643   2147483643 7ffffffb
xx=  2147483644   2147483644 7ffffffc
xx=  2147483645   2147483645 7ffffffd
xx=  2147483646   2147483646 7ffffffe
xx=  2147483647   2147483647 7fffffff
xx= -2147483648   2147483648 80000000
xx= -2147483647   2147483649 80000001
xx= -2147483646   2147483650 80000002
xx= -2147483645   2147483651 80000003
yy=  2147483642   2147483642 7ffffffa
yy=  2147483643   2147483643 7ffffffb
yy=  2147483644   2147483644 7ffffffc
yy=  2147483645   2147483645 7ffffffd
yy=  2147483646   2147483646 7ffffffe
yy=  2147483647   2147483647 7fffffff
yy= -2147483648   2147483648 80000000
yy= -2147483647   2147483649 80000001
yy= -2147483646   2147483650 80000002
yy= -2147483645   2147483651 80000003

 

比較のプログラム
このプログラムからは,2つの変数の比較において,
long intとunsigned long intの違いが起こることがわかる。
long int同士,およびunsigned long int同士では正しく比較できるが
そうでない場合は比較が正しく評価されない。
 

#include <stdio.h>

int main()
{
    long int xx;
    unsigned long int yy;
    xx=yy=-3200;
    printf("xx=%d %u %x\n",xx,xx,xx);
    printf("yy=%d %u %x\n",yy,yy,yy);
    if (3000<xx) printf("3000<xx\n");
    if (3000<yy) printf("3000<yy\n");
    if (xx<-3000) printf("xx<-3000\n");
    if (yy<-3000) printf("yy<-3000\n");


    xx=yy=3200;
    printf("xx=%d %u %x\n",xx,xx,xx);
    printf("yy=%d %u %x\n",yy,yy,yy);
    if (3000<xx) printf("3000<xx\n");
    if (3000<yy) printf("3000<yy\n");
    if (xx<-3000) printf("xx<-3000\n");
    if (yy<-3000) printf("yy<-3000\n");
    xx=yy=4000000000;
    printf("xx=%d %u %x\n",xx,xx,xx);
    printf("yy=%d %u %x\n",yy,yy,yy);
    if (3000<xx) printf("3000<xx\n");
    if (3000<yy) printf("3000<yy\n");
    if (xx<-3000) printf("xx<-3000\n");
    if (yy<-3000) printf("yy<-3000\n");
    return 0;
}







-3200は「2の補数表現」でfffff380である。

xx,yyともにfffff380が代入され,%d,%u,%xで表示された。



負の値を代入したのでsigned long intのxxのみ論理のつじつまが合う。
signed long int変数とlong int定数の混合演算(ここでは比較)は演算結果は不正

3200は2の補数表現でc80である。

xx,yyともにc80が代入され,%d,%u,%xで表示された。




4000000000は「2の補数表現」でee6b2800である。

xx,yyともにee6b2800が代入され,%d,%u,%xで表示された。


long intで扱えない値(unsigned intならOK)なので,
yyと正の値のみ正しい演算(ここでは比較)になっている。

実行結果  
xx=-3200 4294964096 fffff380
yy=-3200 4294964096 fffff380
3000<yy
xx<-3000
yy<-3000
xx=3200 3200 c80
yy=3200 3200 c80
3000<xx
3000<yy
yy<-3000
xx=-294967296 4000000000 ee6b2800
yy=-294967296 4000000000 ee6b2800
3000<yy
xx<-3000
yy<-3000

 

 APPENDIX 6 short int 型変数と unsigned short int 型変数

short int型変数とunsigned short int型変数の振る舞いを見るプログラム

プログラム
printf関数にshort int型変数を表示させる時,変数はlong intに拡張されて値渡しが行われるのがわかる。だから,本来f380のはずの変数の値がfffff380に拡張されて,printfが受け取ることになる。
16進表示では違和感があるが,%d表示では正しく表示され,つじつまが合っている。
16進表示において,16bit分のみを表示させるには表示の際に型キャストして渡せばよい。

#include <stdio.h>

int main()
{
    short int xx;
    unsigned short int yy;
    xx=yy=-3200;
    printf("xx=%6d %12u %8x\n",xx,xx,xx);
    printf("xx=%6d %12u %8x\n",xx,xx,(unsigned short int)xx);
    printf("yy=%6d %12u %8x\n",yy,yy,yy);
    if (3000<xx) printf("3000<xx\n");
    if (3000<yy) printf("3000<yy\n");
    if (xx<-3000) printf("xx<-3000\n");
    if (yy<-3000) printf("yy<-3000\n");
    xx=yy=3200;
    printf("xx=%6d %12u %8x\n",xx,xx,xx);
    printf("yy=%6d %12u %8x\n",yy,yy,yy);
    if (3000<xx) printf("3000<xx\n");
    if (3000<yy) printf("3000<yy\n");
    if (xx<-3000) printf("xx<-3000\n");
    if (yy<-3000) printf("yy<-3000\n");
    xx=yy=50000;
    printf("xx=%6d %12u %8x\n",xx,xx,xx);
    printf("yy=%6d %12u %8x\n",yy,yy,yy);
    if (3000<xx) printf("3000<xx\n");
    if (3000<yy) printf("3000<yy\n");
    if (xx<-3000) printf("xx<-3000\n");
    if (yy<-3000) printf("yy<-3000\n");
    return 0;
}

実行結果
xx= -3200   4294964096 fffff380
xx= -3200   4294964096     f380
yy= 62336        62336     f380
3000<yy
xx<-3000
xx=  3200         3200      c80
yy=  3200         3200      c80
3000<xx
3000<yy
xx=-15536   4294951760 ffffc350
yy= 50000        50000     c350
3000<yy
xx<-3000