JavaScript is required to for searching.
ナビゲーションリンクをスキップ
印刷ビューの終了
Oracle Solaris Studio 12.3: C ユーザーガイド     Oracle Solaris Studio 12.3 Information Library (日本語)
search filter icon
search icon

ドキュメントの情報

はじめに

1.  C コンパイラの紹介

2.  C コンパイラ実装に固有の情報

3.  C コードの並列化

4.  lint ソースコード検査プログラム

5.  型に基づく別名解析

6.  ISO C への移行

6.1 基本モード

6.1.1 -Xc

6.1.2 -Xa

6.1.3 -Xt

6.1.4 -Xs

6.2 新しい形式の関数プロトタイプ

6.2.1 新しいコードを書く

6.2.2 既存のコードを更新する

6.2.3 併用に関する考慮点

6.3 可変引数を持つ関数

6.4 拡張: 符号なし保存と値の保持

6.4.1 若干の背景となる歴史

6.4.2 コンパイルの動作

6.4.3 例: キャストの使用

6.4.4 例: 同じ結果、警告なし

6.4.5 整数定数

6.4.6 例: 整数定数

6.5 トークン化と前処理

6.5.1 ISO C の翻訳段階

6.5.2 古い C の翻訳段階

6.5.3 論理的なソース行

6.5.4 マクロ置換

6.5.5 文字列の使用

6.5.6 トークンの連結

6.6 const と volatile

6.6.1 lvalue 専用の型

6.6.2 派生型の型修飾子

6.6.3 const は readonly を意味する

6.6.4 const の使用例

6.6.5 volatile の使用例

6.7 複数バイト文字とワイド文字

6.7.1 アジア言語は複数バイト文字を必要とする

6.7.2 符号化の種類

6.7.3 ワイド文字

6.7.4 C 言語の機能

6.8 標準ヘッダーと予約名

6.8.1 標準ヘッダー

6.8.2 実装で使用される予約名

6.8.3 拡張用の予約名

6.8.4 安全に使用できる名前

6.9 国際化

6.9.1 ロケール

6.9.2 setlocale() 関数

6.9.3 変更された関数

6.9.4 新しい関数

6.10 式のグループ化と評価

6.10.1 式の定義

6.10.2 K&R C の再配置の権利

6.10.3 ISO C の規則

6.10.4 括弧の使用

6.10.5 as if 規則

6.11 不完全な型

6.11.1 型

6.11.2 不完全な型を完全にする

6.11.3 宣言

6.11.4 式

6.11.5 正当性

6.11.6 例: 不完全な型

6.12 互換型と複合型

6.12.1 複数の宣言

6.12.2 分割コンパイル間の互換性

6.12.3 単一のコンパイルでの互換性

6.12.4 互換ポインタ型

6.12.5 互換配列型

6.12.6 互換関数型

6.12.7 特別な場合

6.12.8 複合型

7.  64 ビット環境に対応するアプリケーションへの変換

8.  cscope: 対話的な C プログラムの検査

A.  機能別コンパイラオプション

B.  C コンパイラオプションリファレンス

C.  ISO/IEC C 99 の処理系定義の動作

D.  C99 の機能

E.  ISO/IEC C90 の処理系定義の動作

F.  ISO C データ表現

G.  パフォーマンスチューニング

H.  Oracle Solaris Studio C: K&R C と ISO C の違い

索引

6.2 新しい形式の関数プロトタイプ

1990 ISO C 規格での最大の変更点は、C++ 言語の機能である関数プロトタイプを使用できることです。各関数のパラメータの数と型を指定することにより、すべての通常のコンパイルは、関数呼び出しごとに (lint のように) 引数とパラメータの検査の利点を得る一方、引数が (代入だけで) 自動的に関数が期待する型に変換されます。プロトタイプを使用するように変更できる (また、変更すべき) 既存の C コードが非常に多く存在するため、1990 ISO C 規格には、古い形式と新しい形式の関数宣言を併用する規則が含まれています。

1999 ISO C 規格によって、古い形式の関数宣言は廃止されました。

6.2.1 新しいコードを書く

まったく新しいプログラムを書くとき、ヘッダーでは、新しい形式の関数宣言 (関数プロトタイプ) を使用し、それ以外の C ソースファイルでは、新しい形式の関数宣言と関数定義を使用します。しかし、ISO C 以前のコンパイラを持つシステムにコードを移植する可能性がある場合は、ヘッダーとソースファイルの両方で、マクロ __STDC__ (ISO C コンパイルシステム専用に定義されている) を使用してください。例については、「6.2.3 併用に関する考慮点」を参照してください。

同じオブジェクトまたは関数に対して 2 つの互換性のない宣言が同じスコープの中にある場合、ISO C 準拠のコンパイラは診断メッセージを発行しなければいけません。すべての関数がプロトタイプで宣言および定義され、適切なヘッダーが正しいソースファイルによってインクルードされている場合、すべての呼び出しは関数の定義に従うはずです。この取り決めによって、起こりがちな C プログラミングの誤りを防ぐことができます。

6.2.2 既存のコードを更新する

既存のアプリケーションがあり、関数プロトタイプの利点が必要な場合、どれくらいのコードを変更するかによって、更新にいくつかの可能性が存在します。

  1. 変更せずに再コンパイルする

    コードを変更しなくても、-v オプションでコンパイラを実行すると、パラメータの型と数の不一致について警告が発行されます。

  2. ヘッダーだけに関数プロトタイプを追加する

    大域的な関数へのすべての呼び出しが診断の対象になります。

  3. ヘッダーには関数プロトタイプを追加し、各ソースファイルの先頭には局所 (静的な) 関数に対する関数プロトタイプを追加する

    関数へのすべての呼び出しが対象になります。ただしこの方法では、ソースファイル内で局所関数ごとに 2 回インタフェースを入力する必要があります。

  4. すべての関数宣言と関数定義を、関数プロトタイプを使用するように変更する

結果として受ける恩恵とそのための負荷を考えると、ほとんどの場合、前述の 2 か 3 が適切な選択だと言えるでしょう。ただしこれらを選択する場合、古い形式と新しい形式を併用するための規則を詳細に知っておく必要があります。

6.2.3 併用に関する考慮点

関数プロトタイプ宣言と古い形式の関数定義がともに機能するためには、両方が機能的に同じインタフェースを指定しなければいけません。つまり、ANSI/ISO C の用語を使用する「互換形式」を持っていなければいけません。

可変引数を持つ関数の場合は、ISO C の省略記号と古い形式の varargs() 関数定義は併用できません。固定数のパラメータを持つ関数の場合、以前の実装で渡したとおりのパラメータの型を指定できます。

K&R C では、各引数は、呼び出された関数に渡される直前に、デフォルトの引数拡張に従って変換されました。 このような拡張は、int より狭いすべての整数型が int サイズに拡張され、また、任意の float 引数が double に拡張されるように指定していたため、コンパイラとライブラリの両方を単純化していました。関数プロトタイプはより表現力が高いです。指定したパラメータの型が関数に渡されるものになるためです。

したがって、関数プロトタイプが既存の (古い形式の) 関数定義のために記述されている場合、その関数プロトタイプには、次のいずれかの型のパラメータを一切含めないようにしてください: char、signed char、unsigned char、float、short、signed short、unsigned short。

プロトタイプを書く際には、依然として 2 つの問題があります。typedef 名と、狭い unsigned 型の拡張規則です。

古い形式の関数内のパラメータが typedef 名を使って宣言されている場合 (off_t や ino_t など)、typedef 名がデフォルトの引数拡張によって影響を受ける型を指しているかどうかを確認する必要があります。これら 2 つの場合、off_t は long で、関数プロトタイプで使用できます。ino_t は unsigned short であったため、プロトタイプで使用すると、古い形式の定義とプロトタイプが異なる互換性のないインタフェースを指定するため、コンパイラは診断メッセージを発行します。

unsigned short の代わりに何を使用すべきかを決定するのは、複雑です。K&R C と 1990 ANSI/ISO C コンパイラ間の最大の非互換性は、unsigned char と unsigned short を int 値に広げるための拡張規則です (「6.4 拡張: 符号なし保存と値の保持」を参照)。この古い形式のパラメータに対応するパラメータ型は、コンパイル時に使用するコンパイルモードによって異なります。

最良の方法は、int または unsigned int のどちらかを指定するように古い形式の定義を変更して、一致する型を関数プロトタイプで使用することです。必要であれば、関数を入力したあとでも、より狭い型の値を局所変数に代入できます。

前処理によって影響を受ける可能性のあるプロトタイプでは、ID の使用に注意を払ってください。次の例を考えてみましょう。

#define status 23
void my_exit(int status);   /* Normally, scope begins */
                            /* and ends with prototype */

関数プロトタイプは、狭い型を持つ古い形式の関数定義と併用できません。

void foo(unsigned char, unsigned short);
void foo(i, j) unsigned char i; unsigned short j; {...}

__STDC__ を適切に使用すれば、古いコンパイラと新しいコンパイラの両方で使用できるヘッダーファイルを作成できます。

header.h:
    struct s { /* .  .  .  */ };
    #ifdef __STDC__
       void errmsg(int, ...);
       struct s *f(const char *);
       int g(void);
    #else
      void errmsg();
      struct s *f();
      int g();
    #endif

次の関数はプロトタイプを使用していますが、古いシステムでもコンパイルできます。

struct s *
#ifdef __STDC__
    f(const char *p)
#else
    f(p) char *p;
#endif
{
    /* .  .  .  */
}

次の例は、更新されたソースファイルを示しています (前述の選択肢 3 と同様)。局所関数は古い形式の定義を使用していますが、新しいコンパイラ用にプロトタイプも含まれています。

source.c:
   #include “header.h”
      typedef /* .  .  .  */ MyType;
   #ifdef __STDC__
      static void del(MyType *);
      /* .  .  .  */
      static void
      del(p)
      MyType *p;
      {
      /* .  .  .  */
      }
      /* .  .  .  */