Programming Place Plus トップページ – C言語編
以下は目次です。
プログラミングでは、普段の生活で使っている 10進数のほか、2進数や 8進数、16進数を使う機会があります。
この章では、C言語での事情に限定した話をします。もし、こういった数の表現に馴染みがない場合は、まず先に、「コンピュータサイエンス編 > 基数」のページをお読みください。
まず、8進数を取り上げます。
C言語のソースコード上では、数値の先頭に「0」を付加すると、その数値を 8進数とみなすことになっています。たとえば、「0100」は、8進数の 100 のことです。浮動小数点数を 8進法では表記できません。
まれに、この表記方法があることを知らなかったり忘れていたりして、ソースコード上の単なる桁数合わせのような感覚で、先頭に 0 を付けてしまうバグを見かけることがあります。「100」のつもりで「0100」と書くと、違う数になってしまうので注意が必要です。
printf関数、scanf関数、sscanf関数は、8進数での入出力にも対応しています。8進数を扱うには、“%o” という変換指定子を使います。ただし、“%o” は負数を扱えません。
たとえば、printf関数で “%o” を試してみます。
#include <stdio.h>
int main(void)
{
("%o\n", 0100);
printf("%o\n", 100);
printf("%d\n", 0100);
printf("%d\n", 100);
printf}
実行結果:
100
144
64
100
ソースコード上の数の表記が何進法であるかと、printf関数の変換指定子を何にするかは対応するわけではありません。ソースコード上では 8進法を使っていても、10進法で表記した出力結果が欲しいのなら “%d” 変換指定子を使います。
また、ソースコード上で「64」と書いても、「0100」と書いても、それは同じ数であることをよく理解してください。異なるのは表記方法であって、数値が違っているのではありません。
“%o” 変換指定子による出力結果の方には、数の先頭に「0」が付加されていません。もし、「0」を付けて欲しいのであれば、変換フラグと呼ばれる文字を付け足して、“#o” という変換を指定します。
#include <stdio.h>
int main(void)
{
("%#o\n", 0100);
printf}
実行結果:
0100
C言語のソースコード上では、数値の先頭に「0x」または「0X」を付加すると、その数値を 16進数とみなすことになっています。たとえば、「0x100」は、16進数の 100 のことです。
浮動小数点数の場合にも 16進数による表記が行えますが、これは記法が特殊なので、第20章で改めて取り上げることにします。
printf関数は、16進数での入出力にも対応しています。16進数を扱うには、“%x” または “%X” という変換指定子を使います。“%x” の場合は「A~F」を小文字で出力し、“%X” の場合は大文字で出力します。なお、“%x” や “%X” は負数を扱えません。
同様に、scanf関数や sscanf関数でも、“%x” や “%X” を使います。こちらは、“%x” と “%X” には違いがなく、「A~F」でも「a~f」でも受け付けてくれます。入力の場合は、区別を付けない方が使いやすいはずです。
printf関数で “%x” と “%X” を試してみます。
#include <stdio.h>
int main(void)
{
("%x\n", 0x1f);
printf("%x\n", 0x1F);
printf("%X\n", 0x1f);
printf("%X\n", 0x1F);
printf}
実行結果:
1f
1f
1F
1F
sizeof演算子を使うと、型の大きさを知ることができます。
型の大きさはバイト単位で表現されますから、大きさが分かれば、その型で表現できる数の範囲も分かります。
sizeof演算子は、以下のいずれかの構文で使用します。
sizeof(型名)
sizeof(式)
sizeof 式
型に応じた大きさ、あるいは式の結果の型の大きさがバイト単位で得られます。型名を指定する場合は ( ) で囲まないといけません。式の場合でも、( ) で囲む方が一般的かと思います。
具体的なコードは次のようになります。
int main(void)
{
size_t a;
= sizeof(int);
a
int num = 0;
= sizeof(num);
a = sizeof num; // 上の行と同じ意味
a }
sizeof演算子に与える式の部分は、ごくわずかな例外的な場面を除いて、実行されません。たとえば、「sizeof(func())」のように使用したとしても、func関数が呼び出されることはありません。
【上級】ごくわずかな例外的な場面は、可変長配列(第25章)を与えた場合です。このときは、式が評価(第27章)されます。
【上級】そもそも、関数を与えるような使い方はまずしませんが、この場合は戻り値の型の大きさが得られます。もし、戻り値の型が void の場合はコンパイルエラーになります。
sizeof演算子で得られる値は、size_t型の定数です。定数なので、コンパイルした時点で、何らかの整数値が得られています。
size_t型は、標準ライブラリの中で定義されているため、使用するためには #include で取り込む必要があります。<stddef.h> をはじめとして、いくつかの標準ヘッダで定義されており、<stdio.h> にも定義されているため、大抵はあまり意識せずに使用できます。
【上級】size_t型は整数を扱う型ですが、C言語に組み込まれている標準的な型ではなく、typedef(第26章)という機能によって作られた、型の別名に過ぎません。
試しに、int型の大きさを出力してみましょう。
#include <stdio.h>
int main(void)
{
( "int型の大きさは %zuByte\n", sizeof(int) );
printf}
実行結果:
int型の大きさは 4Byte
printf関数や scanf関数で size_t型の値を扱う際には、“%zu” という変換指定を使います。
“%zu” は C99規格で追加されました。これが使えない場合は、“%lu” などで代替します
このサンプルプログラムを実行した環境では、int型の大きさが 4バイトだという結果が出ましたが、ほかの環境では結果が異なるかもしれません。
先ほどのサンプルプログラムでは、int型の大きさは 4バイトになりましたが、int型の大きさは明確に定められてはおらず、処理系によって異なります。
明確に決められていることは、-32767~32767 の範囲の値を表現できるだけの大きさがあるという点だけです。この範囲を表現するためには 16ビット必要なので、実質的に、int型は 16ビットよりは大きいことが保証されます。
もし、int型が 4バイト(32ビット)であれば、表現できる値の範囲はどのくらいになるでしょうか?
まず、int型は負数も扱えます。負数の表現には、2の補数表現を使うと仮定すると(この仮定はほとんど確実に正しいです)、最上位ビットは符号の表現に使わなければなりませんから、231 で表現できる数が最大値です。計算すると、最大値は +2,147,483,647 であることが分かります。
最小値の方は、2の補数表現では、正の側よりも 1つ多く表現できるので -2,147,483,648 です。ただし、C言語では、2の補数表現を使うことが強制されているわけではないので、確実に表現できる最小値は -2,147,483,647 です。
よって、32ビットの int型で確実に表現できる値の範囲は、-2,147,483,647~+2,147,483,647 です。
より直接的に限界値を調べる方法を、第19章で後で取り上げます
問題① 標準入力から 16進数の整数を受け取り、それを 8進数で出力するプログラムを作成してください。
問題② 8・10・16進数の対応表を表示するプログラムを作ってください。値の範囲は、10進数で「0~16」とします。
問題③ 次の式を手作業で計算してみてください。そして、答えを確認するためのプログラムを作成してください。
「0x3c5 × 26 - 0741」は 10進数でいくつ?
問題④ 2進数の 0111101 を 10進数と 16進数に変換してください。
return 0;
を削除(C言語編全体でのコードの統一)’2018/6/6 全体的に構成と内容を修正。
「2進数の負の整数」の項を追加。
参考書籍を追加。
’2018/6/5 第19章から移動してくる形で新規作成。
Programming Place Plus のトップページへ