C言語のポインタ変数にはどうして型が必要なのか?

C言語のポインタ変数はメモリ上のアドレス位置を格納する変数です。アドレス位置を格納する場合、ポインタ変数には32bit OSでは4バイト、64bit OSでは8バイトが割り当てられます。これは、32bit OSの場合は2の32乗(約4ギガバイト)までのメモリを扱える(制御できる)ということになります。64bit OSの場合は2の64乗(約18エクサバイト)です。

本題に入る前に以下のプログラムを実行してみて実際の型のサイズを確認してみます。ポインタ変数のサイズの確認ですが、char型、int型、float型、double型のサイズも表示するようにしています。コンパイル、および、実行した環境は64bit Linux(ubuntu)です。


#include <stdio.h>

int main( void )
{
	char  *charp;
	int  *intp;
	float  *floatp;
	double  *doublep;
	void  *voidp;

	printf( "整数型のサイズ\n" );
	printf( "sizeof( char ) = %d\n", (int)sizeof( char ));
	printf( "sizeof( short ) = %d\n", (int)sizeof( short ));
	printf( "sizeof( int ) = %d\n", (int)sizeof( int ));
	printf( "sizeof( long ) = %d\n\n", (int)sizeof( long ));

	printf( "浮動小数点型のサイズ\n" );
	printf( "sizeof( float ) = %d\n", (int)sizeof( float ));
	printf( "sizeof( double ) = %d\n", (int)sizeof( double ));
	printf( "sizeof( long double ) = %d\n\n", (int)sizeof( long double ));

	printf( "ポインタのサイズ\n" );
	printf( "sizeof( charp ) = %d\n", (int)sizeof( charp ));
	printf( "sizeof( intp ) = %d\n", (int)sizeof( intp ));
	printf( "sizeof( floatp ) = %d\n", (int)sizeof( floatp ));
	printf( "sizeof( doublep ) = %d\n", (int)sizeof( doublep ));
	printf( "sizeof( voidp ) = %d\n", (int)sizeof( voidp ));

	return 0;

}

実行した結果は以下です。

整数型のサイズ
sizeof( char ) = 1
sizeof( short ) = 2
sizeof( int ) = 4
sizeof( long ) = 8

浮動小数点型のサイズ
sizeof( float ) = 4
sizeof( double ) = 8
sizeof( long double ) = 16

ポインタのサイズ
sizeof( charp ) = 8
sizeof( intp ) = 8
sizeof( floatp ) = 8
sizeof( doublep ) = 8
sizeof( voidp ) = 8

ここから本題に入ります。ポインタ変数はメモリ上のアドレス位置を格納できれば良いので8バイト分を確保すれば済みます。わざわざchar型のポインタ変数、int型のポインタ変数などと分ける必要があるのでしょうか?

これについては僕が思っている答えを書いておきます。ポインタ変数に格納されているアドレス位置はその変数の開始位置であって、それ以上の情報はありません。実際にプログラムが変数を取り出すには変数の開始位置と終了位置(開始位置からどれだけの領域を確保しているか)の情報が必要です。以下に図で示します。

ポインタは変数の開始位置を指し示していますが、アドレス位置だけでは変数が何バイト分の領域を要しているかはわかりません。この「何バイト分の領域か?」を示すのがポインタ変数の型となります。char型であれば開始位置から1バイト分、int型であれば開始位置から4バイト分となります。ポインタ変数に型を指定することで、ポインタを使用して参照する変数への値の代入や書き換えが可能になると考えます。

C言語のポインタは配列と強い関係性があります。配列の先頭位置をポインタ変数に格納してそれに整数を加算すると、配列の要素を数え上げることになります。

void型のポインタについても書いておきます。void型のポインタは、char、int、float、doubleのどの型のポインタでも格納することができます。ですが、void型のポインタは「開始位置から何バイトを保持しているのか?」の情報を持っていないので、void型のポインタを使用して変数へのアクセス(値の参照や代入など)はできません。

最後に。
C言語を学ぶ上でバイブルと呼ばれている本です。初心者向けの本を一通り読み終えた後に読むと理解が一層深まります(初心者が読むには少し難しい)。かなり昔の本ですが、Cの思想や考え方などは今読んでもとても参考になります。

Javaの利用とサポート期間の振り返り

Javaは以前は無償で使えていたのですが、今は商用利用は有償となっておりサポート期間もバージョンによって違います。Java(Oracle JDK)を使ってみようと思い、今更ながらまとめてみました。

2014年3月 Java8がリリース
Java8までが無償利用が出来て、且つ、バグフィックスやセキュリティパッチの提供も(無償で)受けられたJavaです。6→7→8とメジャーバージョンアップが行われてきましたがバージョンアップの間隔は3〜4年となっていて特に決まっていませんでした。また、次のバージョンが出たからといって前のバージョンのパッチ提供がすぐになくなるということはなかったと思います。今は、商用利用でのJava8のパッチの提供は終了しています(2019年1月に終了)。個人利用の場合は2020年12月までパッチ提供があります。

= = 追記 = =
Java8の個人利用ですが無期限に変更されたようです。パッチ提供をやめる場合は18か月前には通知するようです。2020年5月13日付けの Oracle Java SE Supportロードマップ の抜粋です。

2017年9月 Java9がリリース
Java9からはバージョンアップは半年ごとになりました。パッチのサポートも半年間のみです。Java9を使い始めて半年後にはJava10が出るのでそちらに移行すれば良いわけですが、商用利用している場合はそう簡単に載せ換えられるものでもありません。半年後にパッチのサポートがないからと言ってJava9が使えなくなるというわけではないのですが、商用利用の場合は不安があります。その場合はお金を払うことで(つまり、有償で)Oracleからパッチを提供してもらうことはできます。

2018年9月 Java11がリリース
Java11からは商用でJavaを利用する場合は有償となりました。Oracleとライセンス契約が必要です。非商用(開発環境での利用)もしくは個人利用であれば無償です。またJava11では有償としたためか半年のサポートではなく5年間の長期サポート(LTS:Long Time Support)となっています。Java11以降もJavaのバージョンは半年ごとにあがっていきますが、Java11のようなLTS版は3年ごとに出るようです。次のLTS版はJava17です。non-LTS版も有償ですがサポート期間は半年間です。
個人の場合は無償で利用はできますがOracleからのサポートはなさそうです。

= = 2022年5月追記 = =
2021年9月 Java17がリリース
この記事を執筆した時点ではLTS版は3年ごとのリリースだったのですが、現在では2年ごとのリリースになるようです。ですのでJava17の次のLTS版はJava21になります。ただ、Javaのロードマップの注釈に「LTSの指定と日付は変更される場合があります」のコメントもありました。

2018/09 Java11 LTS
2019/03 Java12 non-LTS
2019/09 Java13 non-LTS
2020/03 Java14 non-LTS
2020/09 Java15 non-LTS
2021/03 Java16 non-LTS
2021/09 Java17 LTS
2022/03 Java18 non-LTS
2022/09 Java19 non-LTS
2023/03 Java20 non-LTS
2023/09 Java21 LTS
2024/03 Java22 non-LTS
2024/09 Java23 non-LTS

Java11以降、商用でJava(Oracle JDK)を利用する場合はタダではなくなったということです。ですが、OpenJDKというものを使えば商用でも無償でJavaが利用できます。OpenJDKは、OpenJDKコミュニティが作成したソースコードをOracle社がビルドしたものなのでOracle JDKとほぼ同じと考えてよいでしょう。ただOpenJDKも半年ごとにバージョンアップが行われていて、パッチも半年間のみの提供です。半年ごとに次のバージョンのOpenJDKに載せ換える手間があります。

ちなみにOracle社の製品(ウェブアプリケーションサーバーのweblogic)を使用している場合は製品のライセンス契約の中にJavaの利用が含まれるようなのでそれを使ってもよいかもしれません。Oracle社の方でweblogicのバージョンとJavaのバージョンとの整合性を確認してくれるようです。

以下はOracle社が行うJavaのサポート期間です(2020年4月現在)。

Premier Support、Extended Support、Sustaining Support の3つがあります。Oracleの「ファースト・ステップ・ガイド 第8版」によると「通常、ソフトウェア製品は出荷開始後の5年間をPremier Support期間とし、包括的なメンテナンスとソフトウェア・アップグレードを提供します。Premier Support期間終了後は、特定のプログラム・リリースについては、追加料金設定により、Premier Supportに準ずるサービス・レベルを維持するExtended Support期間が通常3年間提供されます。Extended Supportが設定されないリリースおよびExtended Support期間の終了後はSustaining Support期間となります。」とあります。

ちなみに、Java8のPremier Support期間が2022年3月までとなっているのが疑問だったのだけれど(Java8の商用利用でのサポートは2019年1月に終了したはず)、、これは本来は無償で使えたJava8を有償でOracle社と契約することでサポートしてもらえるということなのかな?と思いました。