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 constvolatile

6.6.1 lvalue 専用の型

6.6.2 派生型の型修飾子

6.6.3 constreadonly を意味する

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.10 式のグループ化と評価

K&R C は、数学的に交換可能で結合可能な隣り合う演算子を含む式を再配置する権利を、括弧がある場合でもコンパイラに与えます。しかし、ISO C は、この権利をコンパイラに与えませんでした。

この節では、前述の 2 つの C の定義間の違いを説明します。また、次のコードにおける式文を考えることによって、式の副作用、グループ化、および評価の間の区別を明らかにします。

int i, *p, f(void), g(void);
/*...*/
i = *++p + f() + g();

6.10.1 式の定義

式の副作用とは、メモリーへの変更と、volatile 修飾オブジェクトへのアクセスのことです。サンプル式の副作用は、ip の更新と、関数 f()g() 内に含まれる任意の副作用です。

式のグループ化とは、値をほかの値や演算子と結合させる方法です。サンプル式のグループ化は、主に加算を実行する順番です。

式の評価には、その結果の値を生成するために必要なすべてが含まれます。式を評価するためには、指定したすべての副作用が以前のシーケンスポイントから次のシーケンスポイントまでの間で発生しなければならず、指定した演算が特定のグループ化で実行されなければいけません。サンプル式の場合、ip の更新は、直前の文からこの式文の ; までの間で発生する必要があります。関数への呼び出しは、直前の文から戻り値が使用されるまでの間であれば、どちらが先に発生してもかまいません。特に、メモリーを更新する演算子には、演算の値が使用される前に新しい値を代入しなければならないという制約はありません。

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

サンプル式では加算が数学的に交換可能で結合可能であるため、K&R C の再配置の権利がサンプル式に適用されます。通常の括弧と実際の式のグループ化を区別するために、左右の中括弧でグループ化を示します。この式の場合、次の 3 つのグループ化が考えられます。

i = { {*++p + f()} + g() };
i = { *++p + {f() + g()} };
i = { {*++p + g()} + f() };

前述のすべてのグループ化は、K&R C の規則であれば有効です。さらに、たとえば、次のように式を書き換えた場合でも、前述のすべてのグループ化は有効です。

i = *++p + (f() + g());
i = (g() + *++p) + f();

オーバーフローによって例外が発生するか、あるいは、オーバーフローで加算と減算が逆にならないアーキテクチャー上でこの式が評価される場合、加算の 1 つがオーバーフローしたとき、前述の 3 つのグループ化の動作は異なります。

このようなアーキテクチャー上では、K&R C では、式を分割することによって強制的にグループ化するしか方法がありません。次の書き換え案はそれぞれ、前述の 3 つのグループ化を強制的に行います。

i = *++p; i += f(); i += g()
i = f(); i += g(); i += *++p;
i = *++p; i += g(); i += f();

6.10.3 ISO C の規則

ISO C では、数学的に交換可能で結合可能であるが、対象となるアーキテクチャー上では実際にそうではない演算を再配置することは許可されていません。したがって、ISO C 文法の優先度と結合規則によって、すべての式のグループ化が完全に記述されます。すべての式は、解析されるとおりにグループ化されなければいけません。前述の式は、次の方法でグループ化されます。

i = { {*++p + f()} + g() };

このコードでもなお「f()g() よりも前に呼び出されなければならない」、あるいは、「g() が呼び出されるよりも前に p が増分されなければならない」ということはありません。

ISO C では、予想外のオーバーフローが発生しないように式を分割する必要があります。

6.10.4 括弧の使用

ISO C では、不十分な理解と不正確な表現のために、括弧の信頼性と括弧に従った評価について、間違って記述されることがしばしばあります。

ISO C 式は解析によって指定されるグループ化を持つため、括弧は、式の解析方法を制御する手段としての役割しか果たしません。式の自然な優先度と結合規則が、括弧とまったく同じ重要性を持ちます。

前述の式は、グループ化や評価に対する効果を一切変えずに、次のように記述することもできました。

i = (((*(++p)) + f()) + g());

6.10.5 as if 規則

K&R C の再配置規則の理由を、次にいくつか示します。

ISO C 委員会は、記述される対象アーキテクチャーに適用されるときに、再配置規則は「as if」規則のインスタンスになるものであると、最終的に決定しました。ISO C の「as if」規則は、有効な C プログラムの動作を変更しないかぎり、実装が必要に応じて抽象マシン記述から離れることを一般的に許可しています。

したがって、すべてのビット単位の 2 項演算子 (シフトを除く) は任意のマシンで再配置できます。これは、そのような再グループ化は確認不可能であるためです。2 の補数を使用するマシンでオーバーフローが発生しない場合は、いくつかの理由のため、乗算または加算を含む整数式は再配置できます。

したがって、C におけるこの変更は、ほとんどの C プログラマには重要な影響を与えません。.