C++ 移行ガイド

第 4 章 入出力ストリームとライブラリヘッダーの使い方

この章では、C++ 5.0 でのライブラリとヘッダーファイルの変更点について説明します。

入出力ストリーム

C++ 4.2 コンパイラには、これまで正式な定義ではなかった「従来型」の入出力ストリームが実装されています。この実装形式は、Cfront (1990 年) とともにリリースされたバージョンと互換性があり、いくつかの問題点が解決されています。

標準 C++ では、新しい入出力ストリームと拡張された入出力ストリーム (標準入出力ストリーム) が定義されています。新しい入出力ストリームは、綿密に定義されており、機能が豊富で、多言語化対応のコードの記述に利用できます。

C++ 5.0 コンパイラの互換モードでは、C++ 4.2 で提供されるものと同じ従来型の入出力ストリームがサポートされています。4.2 コンパイラで動作する既存の入出力ストリームはどれも、5.0 の互換モードでも同様に動作します。

新バージョンの入出力ストリームには、標準モードでアクセスできます。標準の入出力ストリームにアクセスするには、<iostream><fstream><sstream> などの新しい形式の標準ヘッダーを使用します。新しい形式のヘッダー名の末尾が .h ではないことに注意してください。

標準モードでは、デフォルトで標準の入出力ストリームが使用されます。標準形式のヘッダー名 (「.h」なし) を使用すると、標準ヘッダーが使用されます。その場合、すべての宣言は名前空間 std にあります。

それぞれの標準ヘッダーは「.h」で終わる形式のものも用意されています。これを使用すると、すべてのヘッダー名が using 宣言によって大域名前空間に存在するようになります。これらのヘッダーはサンの拡張であるため、これに依存するコードは移植性がない可能性があります。これらのヘッダーを使用すると、従来の入出力ストリームの代りに標準の入出力ストリームを使用している場合でも、既存の (簡単な) 入出力ストリームコードを変更せずにコンパイルできます。たとえば、次の下のコードは、従来の入出力ストリームでもサンの標準入出力ストリームの実装でもコンパイルできます。

標準の名前形式の iostream を使用 - hello1.cc


#include <iostream>
int main()
{
    std::cout << "Hello, world!" << std::endl;
}

従来の名前形式の iostream を使用 - hello2.cc


#include <iostream.h>
int main()
{
    cout << "Hello, world!" << endl;
}

すべての従来の入出力ストリームコードが標準入出力ストリームと互換性があるとは限りません。従来の入出力ストリームコードをコンパイルできない場合は、コードを変更するか、従来の入出力ストリームだけを使用する必要があります。

従来の入出力ストリームを標準モードで使用する場合は、コンパイラオプション library=iostreamCC コマンド行に指定します。このオプションを使用すると、従来の入出力ストリームのヘッダーファイルが入った特別なディレクトリが探索され、従来の入出力ストリーム実行時ライブラリがプログラムとリンクされます。このオプションは、プログラムに必要なすべてのコンパイルだけでなく、最後のリンク段階でも使用する必要があります。そうしないと、一貫性のない結果となります。


注 -

古い形式と新しい形式の入出力ストリーム (標準の入力ストリームと出力ストリーム cincoutcerr を含む) が同じプログラムに混在していると、重大な問題が発生することがあるのでお勧めできません。


タスク (コルーチン) ライブラリ

<task.h> ヘッダーを介してアクセスするコルーチンライブラリはサポートされていません。コルーチンライブラリに比べて、Solaris のスレッドと、言語開発ツール (特にデバッガ) およびオペレーティングシステムとの間の統合が改善されています。

Rogue Wave Tools.h++

Sun C++ 4.2 コンパイラでは、バージョン 7 の Rogue Wave Tools.h++ がデフォルトで提供されていました。また、旧リリースのコンパイラとの互換性を維持するために、バージョン 6 の Tools.h++ も提供されていました。

C++ 5.0 コンパイラでは、バージョン 6 の Tools.h++ は提供されません。バージョン 7 だけが提供されます。互換および標準のどちらのモードでも、C++ 5.0 コンパイラのデフォルトはバージョン 7 の Tools.h++ です。

RogueWave Tools.h++ バージョン 7 ライブラリは、従来の入出力ストリームで構築されています。したがって、RogueWave Tools ライブラリを標準モードでインクルードする場合は、入出力ストリームもインクルードする必要があります。ただし、古い形式と新しい形式の入出力ストリーム (標準の入力ストリームと出力ストリーム cincoutcerr を含む) を同じプログラムで使用しないように注意が必要です。これらが混在していると、重大な問題を引き起こすことがあるのでお勧めできません。

RogueWave Tools.h ライブラリを標準モードで使用する場合は、次のコンパイラオプションを使用します。

RogueWave Tools.h ライブラリを互換モードで使用する場合は、次のコンパイラオプションを使用します。

Tools.h++ へのアクセス方法の詳細については、『C++ ユーザーズガイド』または CC.1 マニュアルページを参照してください。

C ライブラリヘッダー

互換モードでは、これまでとまったく同じ方法で C 標準のヘッダーを使用できます。標準ヘッダーは、 使用中のリリースの Solaris に含まれる /usr/include ディレクトリにあります。

ここで説明する C ライブラリヘッダーとは、ISO C 標準 (1990 年の ISO 9899) と、それ以降の追補 (1994 年) で定義されている以下の 17 のヘッダーです。


<assert.h> <ctype.h>  <errno.h>  <float.h>  <iso646.h> <limits.h>
<locale.h> <math.h>   <setjmp.h> <signal.h> <stdarg.h> <stdio.h>
<stdlib.h> <string.h> <time.h>   <wchar.h>  <wctype.h>

/usr/include ディレクトリとその下位ディレクトリに存在する、その他の数百のヘッダーは、C 言語標準に規定されていないため、この言語の変更による影響を受けることはありません。

C++ 標準では、C 標準のヘッダーの定義が変更されています。

これらのヘッダーは、旧リリースの Sun C++ と同様の方法で C++ プログラムにインクルードして使用することができますが、以下のことに注意してください。

C++ 標準では、型、オブジェクト、これらのヘッダー中で使用する関数名は、大域的な名前空間だけでなく、std 名前空間にも記述するよう規定しています。つまり、Solaris (Solaris 7 も含む) に付属しているヘッダーはそのままでは使用できないということです。標準モードでコンパイルする場合は、C++ 5.0 コンパイラに付属しているヘッダーを使用してください。ヘッダーが正しくないと、プログラムのコンパイルやリンクが失敗する可能性があります。

唯一の制限として、ヘッダーにはパス名ではなく標準のヘッダー名を使用してください。次の文は正しい例です。


#include <stdio.h> // 正しい

次の文は正しくない例です。


#include“/usr/include/stdio.h”    // 誤り
#include </usr/include/stdio.h> // 誤り

C++ 標準では、17 個ある C 標準のヘッダーのすべてに、別のバージョンのヘッダーが追加されています。つまり、<NAME.h> 形式のすべてのヘッダーについて、ヘッダー名の最後の .h を落とし、先頭に c を追加した <cNAME> という形式の名前を持つヘッダーがあります (NAME は名前を示します)。例:<cstdio><cstring><cctype>

新しいバージョンのヘッダーには、従来の形式のヘッダーで使用されていた名前が含まれていますが、新しいバージョンのヘッダーは std 名前空間にのみ存在します。次に、C++ 標準に則った使用例を示します。


#include <cstdio>
int main() { 		
    printf(“Hello,”);            // エラー、printf が不明
    std::printf(“world!¥n”);     // OK
}

<stdio.h> の代わりに <cstdio> が使用されているため、printf という名前は、名前空間 std にあるだけで、大域的な名前空間にはありません。printf の名前を修飾するか、using 宣言を追加する必要があります。


#include <cstdio>
using std::printf;
int main() {
    printf(“Hello,”);            // OK
    std::printf(“world!¥n”);     // OK
}

/usr/include 中の C 標準のヘッダーには、C 標準では使用が許可されていない宣言が多数含まれています。これらの宣言が存在しているのは、慣習上の理由によります。つまり、UNIX システムにおいては、これらのヘッダー中で慣例的に標準外の宣言が使用されてきたということ、また、他の標準 (POSIX や XOPEN など) においては、そうした宣言が必要になるためです。互換性を維持するため、Sun C++ の <NAME.h> ヘッダーには、そうした名前が残されていますが、これらの名前は、大域的な名前空間にしか存在せず、新しいバージョンの <cNAME> ヘッダーには存在しません。これは、新しいヘッダーが以前のプログラムには使用されていないため、互換性や慣習上の問題が生じることはないためです。<cNAME> は、一般的なプログラミングに役立たないと思われるかもしれませんが、最大の移植性を持つ標準的な C++ コードを作成するには、<cNAME> ヘッダーに移植不可能な宣言が含まれないようにする必要があります。<stdio.h> を使用した例を次に示します。


#include <stdio.h>                  // 大域的な名前空間の stdin
int f() { return fileno(stdin); }       // OK
int g() { return std::fileno(stdin); }  // エラー

次の例では、<cstiod> を使用しています。


#include <cstdio>                        //名前空間 std の stdin
int f() { return fileno(std::stdin); }       //エラー
int g() { return std::fileno(std::stdin); }  //エラー

上記の例の中の fileno は、互換性を維持するために <stdio.h> に残されている「標準外」の関数です。この関数は、大域的な名前空間にのみ存在し、std 名前空間には存在しません。標準外の関数であるため、<cstdio> にも存在しません。


注 -

Solaris 2.5.1 および 2.6 では、C++ 5.0 の C 標準のヘッダーは、必ずしもすべての点で C++ 標準に準拠しているわけではありません。


C++ 標準では、同じコンパイル単位で <NAME.h><cNAME> の両方のバージョンの C 標準ヘッダーを使用することを許可しています。一般的に、このことが意図的に行われることはないと思われますが、たとえば、使用するプロジェクトヘッダーに <stdlib.h> が含まれていて、作成したコードに <cstdlib> がインクルードされたときには、このことが起こります。Solaris 2.5.1 と 2.6 環境では、いくつかのヘッダー、特に <wchar.h><cwchar><wctype.h><cwctype> ヘッダーの組み合わせについては機能しません。これらのヘッダーを使用したときにコンパイラのエラーが出力された場合は、<cNAME> 版ではなく、<NAME.h> 版のヘッダーを使用してください。

標準ヘッダーの実装

『C++ ユーザーズガイド』には、標準ヘッダーの実装方法とともに、その方法が採用された理由が詳細にわたって説明されています。C または C++ 標準のヘッダーをインクルードした場合、コンパイラは実際には指定された名前の後に .SUNWCCh が付いた名前を持つファイルを検索します。たとえば、<string> であれば <string.SUNWCCh><string.h> であれば <string.h.SUNWCCh> を検索します。コンパイラの include ディレクトリには、この両方の名前が含まれており、2 つの名前のどちらも同じファイルを示します。たとえば、include/CC ディレクトリには、stringstring.SUNWCCh の両方が含まれており、これらの名前は同じファイル (<string> をインクルードしたときにアクセスされるファイル) を示します。

エラーメッセージとデバッグ情報には、.SUNWCCh という接尾頭辞は追加されません。たとえば、<string> をインクルードした場合、エラーメッセージとデバッグ情報には、string とだけ示されます。接尾頭辞なしの名前に関するデフォルトのメークファイル規則で問題が起きるのを避けるため、ファイル依存情報には、string.SUNWCCh が使用されます。たとえば、Sun OS の find コマンドを使用して、単にヘッダーファイルだけ探す場合は、.SUNWCCh 接頭辞で検索するようにしてください。