JavaScript is required to for searching.
ナビゲーションリンクをスキップ
印刷ビューの終了
Oracle Solaris Studio 12.2: C ユーザーガイド
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 例 1 : キャストの使用

6.4.4 ビットフィールド

6.4.5 例 2 : 同じ結果

6.4.6 整数定数

6.4.7 例 3 : 整数定数

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 constvolatile

6.6.1 右辺値 (lvalue) 専用の型

6.6.2 派生型の型修飾子

6.6.3 constreadonly を意味する

6.6.4 const の使用例

6.6.5 volatile は文字どおりの解釈を意味する

6.6.6 volatile の使用例

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

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

6.7.2 符号化の種類

6.7.3 ワイド文字

6.7.4 変換関数

6.7.5 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.  K&R Solaris Studio C と Solaris Studio ISO C の違い

索引

6.5 トークン化と前処理

以前のバージョンの C でもっとも不明確な仕様は、各ソースファイルを文字の集合から一連のトークンに変換して構文解析できるようにするまでの操作でしょう。具体的には、空白 (コメントも含む) の認識、連続した文字のトークン化、前処理指令行の処理、およびマクロの置換などがあります。しかし、これら操作の優先順位は保証されていませんでした。

6.5.1 ISO C の翻訳段階

ISO C では、このような翻訳段階の順番が指定されています。

ソースファイル内のすべての 3 文字表記シーケンスが置換されます。ANSI/ISO C は、9 つの 3 文字表記シーケンスを持っています。これらのシーケンスはもともと文字セットの不完全な点を補うために導入されました。しかし、現在では、この 3 文字シーケンスは ISO 646-1983 文字セットに含まれない文字を指定するために使用されています。

表 6-1 3 文字シーケンス

3 文字シーケンス
変換後の文字
??=
#
??-
~
??(
[
??)
]
??!
|
??<
{
??>
}
??/
\
??’
^

ISO C コンパイラは前述のシーケンスを理解するはずです。しかし、これらのシーケンスを使用することはお勧めしません。-xtransition オプションを使用したとき、移行モード (-Xt) では、ISO C コンパイラは 3 文字シーケンスを置換するたびに警告を発行します (コメント内でも)。たとえば、次の例を考えてください。

/* comment *??/
/* still comment? */

??/ はバックスラッシュになります。この文字とそれに続く改行は削除されます。結果として、次のようになります。

/* comment */* still comment? */

2 行目の最初の / は、コメントの終わりです。次のトークンは * です。

  1. バックスラッシュと改行文字の組み合わせがすべて削除されます。

  2. ソースファイルが前処理トークンと空白文字のシーケンスに変換されます。各コメントは必要最低限の空白文字で置換されます。

  3. すべての前処理指令が処理され、すべてのマクロ呼び出しが置換されます。#include でインクルードされた各ソースファイルは、内容が指令行に置換される前の初期段階で実行されます。

  4. すべてのエスケープシーケンス (文字定数と文字列リテラル) が解釈されます。

  5. 隣接する文字列リテラルが連結されます。

  6. すべての前処理トークンが通常のトークンに変換されます。コンパイラはこれらのトークンを適切に構文解析して、コードを生成します。

  7. すべての外部オブジェクトと関数参照が解釈処理され、最終的なプログラムになります。

6.5.2 古い C の翻訳段階

以前の C コンパイラは、このような単純な順番に従いませんでした。また、これらの段階がいつ適用されるかも保証されていませんでした。コンパイラとは別のプリプロセッサが、マクロを置換して指令行を処理するときに、トークンと空白を認識していました。そして、コンパイラがプリプロセッサの出力を適切に再トークン化し、言語を構文解析し、コードを生成していました。

プリプロセッサ内のトークン化処理は必要に応じて行われる操作で、マクロ置換は (トークンベースではなく) 文字ベースの操作として行われます。したがって、前処理中にトークンと空白は大きく変動する可能性がありました。

2 つの方法の間には、いくつか異なる点があります。この節の後半では、マクロ置換中に発生する行の連結、マクロ置換、文字列化、およびトークンの連結によって、コードの動作がどのように変化するかを説明します。

6.5.3 論理的なソース行

K&R C では、バックスラッシュと改行を組み合わせた次の行には、指令、文字列リテラル、文字定数しか指定できませんでした。ANSI/ISO C ではこの概念が拡張され、バックスラッシュと改行の組みの次の行に、あらゆるものを指定できるようになりました。K&R では 1 行は 1 行でしたが ANSIC では複数行組み合わせて 1 行とでき、これが論理行です。したがって、バックスラッシュと改行の組み合わせのどちら側にあるかによってトークンの認識が異なるコードは、期待どおりに動作しません。

6.5.4 マクロ置換

ISO C 以前には、マクロ置換処理については詳細に定義されていません。この曖昧さのために、処理系に多くの差が生まれました。したがって、明白な定数置換や簡単な関数のようなマクロよりも複雑なものを持つコードは、おそらく完全には移植できません。このマニュアルでは、古い C と ISO C 間のマクロ置換実装の違いをすべて説明することはできません。ほとんどすべてのマクロ置換の結果は、前とまったく同じトークンの連続になります。ただし、ISO C マクロ置換アルゴリズムは、古い C ではできなかったことができます。たとえば、次を見てください。

#define name (*name)

この例は、すべての namename 経由の間接参照で置換します。古い C プリプロセッサは数多くの括弧とアスタリスクを生成し、ときには、マクロの再帰についてエラーを生成する場合もあります。

ANSI/ISO C によるマクロ置換方法の主な変更は、マクロ置換演算子 ### のオペランド以外のマクロ引数が要求であること、置換トークンリストでの置換前に再帰的に展開することです。ただし、この変更によって、実際に生成されるトークンに差が生じることは滅多にありません。

6.5.5 文字列の使用


注 - ISO C では、-xtransition オプションを使用するとき、次の例 (?) を使用すると、古い機能を使用しているという警告が生成されます。移行モード (-Xt-Xs) の場合のみ、結果は以前のバージョンの C と同じになります。


K&R C では、次のコードは文字列リテラル「"x y!"」を生成しました:

#define str(a) "a!"   ?
str(x y)

プリプロセッサは、文字列リテラルと文字定数の内部で、マクロパラメータのように見える文字を検索していました。ISO C はこの機能の重要性を認識していましたが、トークンの部分にこの操作を行うことはできませんでした。ISO C では、前述のマクロの呼び出しはすべて文字列リテラル「a!」を生成します。ISO C で以前の効果を得るためには、# マクロ置換演算子と文字列リテラルの連結を使用してください。

#define str(a) #a "!"
str(x y)

前述のコードは、2 つの文字列リテラル "x y" "!" を生成し、 連結したあと、同じ文字列 "x y!" を生成します

文字定数用の操作を完全に代用するものはありません。この機能の主な使用方法は次のようなものでした。

#define CNTL(ch) (037 & ’ch’)    ?
CNTL(L)

これは、次を生成します。

(037 & ’L’)

これは、ASCII の Control-L 文字と同じです。最良の解決策は、このマクロを次のように変更することです。

#define CNTL(ch) (037 & (ch))
CNTL(’L’)

このコードの方が読みやすく式にも適用できるため、より使いやすくなっています。

6.5.6 トークンの連結

K&R C では、2 つのトークンを連結するために、少なくとも 2 つの方法がありました。次の 2 つの呼び出しは、2 つのトークン x1 から 1 つの識別子 x1 を生成します。

#define self(a) a
#define glue(a,b) a/**/b ?
self(x)1
glue(x,1)

ISO C では、どちらの方法も使用できません。ISO C では、前述の呼び出しは、両方とも 2 つの別々のトークン x1 を生成します。しかし、前述の呼び出しの内 2 番目の方法については、## マクロ置換演算子を使用すれば、ISO C 用に書き換えることができます。

#define glue(a,b) a ## b
glue(x, 1)

# と ## は、__STDC__ が定義されているときだけ、マクロ置換演算子として使用しなければいけません。## は実際の演算子のため、定義と呼び出しの両方で空白をより自由に使うことができます。

コンパイラは、未定義の ## 演算に対して警告の診断を発行するようになりました (C 規格、3.4.3 節)。未定義とは、## を前処理したときの結果に、単一のトークンではなく、複数のトークンが含まれていることを意味します (C 規格、6.10.3.3(3) 節)。未定義の ## 演算の結果は、現在では、## のオペランドを連結することによって作成された文字列をプリプロセスすることによって生成された個別のトークンのうち最初のものと定義されます。

前述の古い形式の連結方法のうち、最初の方法を直接代用できる方法はありません。しかし、この方法では呼び出し時に連結の処理が必要なため、ほかの方法に比べてあまり使用されることはありませんでした