「C言語/前処理指令」の版間の差分

削除された内容 追加された内容
.旻 (トーク | 投稿記録)
pre -> source
.旻 (トーク | 投稿記録)
書き換えツールのコピペミス
1 行
<ref>『JISX3010:2003』p.6「5.1.1.2 翻訳フェーズ」</ref>
== 関数の基本 ==
<ref>『JISX3010:2003』p.34110「6.3.2.110 左辺値、配列及び関数前処理定子」</ref>
<ref>『JISX3010:2003』p.51「6.5.2.2 関数呼び出し」</ref>
<ref>『JISX3010:2003』p.89「6.7.5.3 関数宣言子」</ref>
<ref>『JISX3010:2003』p.107「6.9.1 関数定義」</ref>
 
前処理指令とは、#前処理字句で始まり、それに続く最初の改行文字で終わる一連の前処理字句である。
C言語のプログラムは全て1つ以上の関数と呼ばれる処理単位から構成される。
前処理指令は、翻訳フェーズの(4)において実行される。
関数とは、識別子を持ち、いくつかの文がブロックでまとめられた、サブルーチンである。
前処理指令によって、
関数を用いることによって、同じ処理をまとめて書くことができ、以後その関数を呼び出すだけでまとめられた処理が実行できるようになる。
ソースファイルの一部分を条件によって処理したり読み飛ばしたり、
関数の記述は次のようになっている。
他のソースファイルを組み込んだり、
マクロを置き換えたりすることができる。
これらの処理は、概念的にはその翻訳単位の翻訳の前に行うので、前処理と呼ぶ。
 
== 条件付き取り込み ==
<ref>『JISX3010:2003』p.112「6.10.1 条件付き取り込み」</ref>
 
条件付き取り込みとは、ソースファイルの一部分を条件によって処理したり読み飛ばしたりする前処理指令である。
 
条件付き取り込みの記述は次のようになっている。
<source lang=c>
#if 定数式1
返却値のデータ型 関数の識別子(任意個数の仮引数)
グループ1
{
#elif 定数式2
/*いくつかの文*/
グループ2
}
#else
グループ3
#endif
</source>
 #if,#elif,#elseは、それぞれ制御文のif,else if,elseと同様の使い方をする。
関数の識別子とはその関数を他の関数と区別するために付ける名前のことで、
すなわち、定数式1が真(0以外)の場合グループ1が実行され、
関数の識別子に使えるのは半角英数、「_(下線)」である。
それ以外の場合で定数式2が真(0以外)の場合グループ2が実行され、
ただし、先頭は非数字でなければならない。
さらにそれ以外の場合グループ3が実行される。
多バイト文字を使用できるかはコンパイラによる。
 
関数は他の関数の中で呼び出すことができる。
定数式では次の形式の単項演算子式を含んでもよい。
関数を呼び出す際、関数の呼び出し元から呼び出し先へ情報を渡すことができ、この情報を引数と呼ぶ。
また、関数の呼び出し先から呼び出し元へ情報を渡すこともでき、この情報を返却値と呼ぶ。
返却値のデータ型で返却値の有無や種類を決定する。
任意個数の仮引数で仮引数の数や種類を決定する。
仮引数の記述は次のようになっている。
<source lang=c>
仮引数のデータ型defined 仮引数の識別子
defined (識別子)
</source>
defined単項演算子は、
仮引数を持たない場合、何も書かない。
識別子がその時点でマクロ名として定義している場合1と評価し、
複数の仮引数を持つ場合、「,(コンマ)」で区切る。
そうでない場合0と評価する。
 
また、次の形式の前処理指令もある。
<source lang=c>
#ifdef 識別子
//例 2つの整数を引数にとりその和を返却する関数
グループ
int function(int a, int b)
#endif
{
return a+b;
}
</source>
これは次の前処理指令と等価である。
 
関数を呼び出す際の記述は次のようになっている。
<source lang=c>
#if defined 識別子
関数の識別子(任意個数の実引数);
グループ
#endif
</source>
 
任意個数の実引数について、
実引数を持たない場合、何も書かない。
複数の実引数を持つ場合、「,(コンマ)」で区切る。
 
<source lang=c>
#ifndef 識別子
//例 上の例の関数を呼び出す
グループ
int function(int a, int b)
#endif
{
return a+b;
}
 
int main(void){
int r;
r=function(1,2);//rには1と2との和である3が代入される。
}
</source>
の例で、function関数実引数前処理指令と等価である1,2が、
function関数の仮引数であるa,bにコピーされ、
a+bがfunction関数の返却値として返され、
その値がrに代入される。
 
== 実行環境 ==
=== フリースタンディング環境 ===
<ref name="規格合致性">『JISX3010:2003』p.5「4 規格合致性」</ref>
<ref name="実行環境">『JISX3010:2003』p.8「5.1.2 実行環境」</ref>
 
オペレーティングシステムのいかなる支援もなしにCプログラムを実行する環境を、
フリースタンディング環境という。
フリースタンディング環境では、
プログラムの開始時に呼び出される関数の名前および型は処理系定義である。
また、複素数型を使っていない。
フリースタンディング環境でプログラムが利用できるライブラリ機能は、
<float.h>, <iso646.h>, <limits.h>, <stdarg.h>,
<stdbool.h>, <stddef.h>, <stdint.h>
であり、これ以外は処理系定義である。
 
=== ホスト環境 ===
<ref name="規格合致性"/>
<ref name="実行環境"/>
 
オペレーティングシステムの支援ありでCプログラムを実行する環境を、
ホスト環境という。
ホスト環境では、プログラム開始処理において呼び出される関数の名前はmainである(エントリポイント)。
 
main関数とはプログラムの開始処理において、
いろいろな初期化処理の後、最初に呼び出される関数である。
たいていのプログラムはこのmain関数から始まると考えてよい。
main関数には大まかに分けてプログラム仮引数(コマンドライン引数)を持たない関数と持つ関数との2種類の記述方法がある。
 
*プログラム仮引数とは
プログラムを実行する際、プログラムに対して渡される情報を、プログラム仮引数と呼ぶ。
例えばコマンドプロンプトにおいて、
<source lang=c>
#if !defined 識別子
C:\example.exe ABC DEF GHI
グループ
#endif
</source>
のようにプログラムを実行した場合、
example.exeプログラムのmain関数に対して、
「example.exe」、「ABC」、「DEF」、「GHI」という4個の文字列が渡される。
 
=== インクルードガード ===
*プログラム仮引数を持たない関数
インクルードガードとは、複数回ヘッダファイルをインクルードすることを防止する方法である。
プログラム仮引数を使用しない場合、次のように仮引数をもたない関数を記述する。
インクルードガードの記述は次のようになっている。
 
<source lang=c>
#ifndef インクルードガード用の識別子
int main(void)
#define インクルードガード用の識別子
{
/*
/*いくつかの文*/
ソースコード
}
*/
#endif
</source>
このヘッダファイルをインクルードする際、
2回目以降は「インクルードガード用の識別子」が定義されているため、
ソースコードが読み飛ばされる。
 
また、コンパイラによっては次のようなインクルードガードの記述もある。
*プログラム仮引数を持つ関数
プログラム仮引数を使用する場合、次のように2つの仮引数をもつ関数を記述する。
<source lang=c>
#pragma once
int main(int argc, char *argv[])
{
/*いくつかの文*/
}
</source>
argcはプログラム仮引数の個数である。
argvはプログラム仮引数を表す文字列の配列へのポインタである。
argv[0]が指す文字列はプログラム名である。
argcにはこのプログラム名も個数として数えられる。
ただし、argcが0の場合、argv[0]は空ポインタである。
またargc>0であっても、ホスト環境からプログラム名が得られない場合、
argv[0]は空ポインタである。
<ref>『[迷信] argv[0] はプログラム名 | 株式会社きじねこ』http://www.kijineko.co.jp/tech/superstitions/argv0-is-program-name.html</ref>
argv[1]からargv[argc-1]までが指す文字列は、プログラム仮引数である。
argv[argc]は空ポインタである。
 
== ソースファイル取り込み ==
ホスト環境では、プログラムは、全てのライブラリ機能を使用してよい。
<ref>『JISX3010:2003』p.113「6.10.2 ソースファイル取り込み」</ref>
 
ソースファイル取り込みとは、他のソースファイルを取り込む前処理指令である。
ホスト環境では、main関数の返却値が、このプログラムを実行するオペレーティングシステムに対して渡され、0はプログラムの成功終了状態を表している。
main関数を終了する}に到達した場合、main関数は値0を返す。
 
ソースファイル取り込みの記述は次のようになっている。
== 引数と返却値をもたない関数 ==
<source lang=c>
#include <h文字列>
//例 引数と返却値をもたない関数
又は
#include <stdio.h>
#include "q文字列"
</source>
 
 #indlude前処理指令は、
void HelloWorld()
h文字列ではヘッダを、q文字列ではソースファイルをそれぞれ取り込む。
{
「#include "q文字列"」の探索をサポートしていない場合や、探索が失敗した場合は、
printf("Hello, World!\n");
同じ文字列を「#include <h文字列>」と読み替えたのと同じ規則で再処理する。
}
 
== マクロ置き換え ==
int main(void)
<ref>『JISX3010:2003』p.114「6.10.3 マクロ置き換え」</ref>
{
HelloWorld();
}
</source>
この例では自作のHelloWorld関数を使って文字列を表示している。
このHelloWorld関数は引数と返却値をもたない関数である。
このプログラムでは、
まずmain関数が呼ばれ、
次にmain関数内のHelloWorld関数を呼ぶ文が実行されることでHelloWorld関数が呼ばれ、
HelloWorld関数内のprintf関数を呼ぶ文が実行されることでprintf関数が呼ばれる。
そしてprintf関数が終了してHelloWorld関数に戻り、
HelloWorld関数が終了してmain関数に戻り、
main関数が終了してプログラムが終了する。
 
マクロ置き換えとは、マクロ名を置換要素並びで置き換える前処理指令である。
この例では関数を自作したメリットはないが、
同じ処理がソースコードのあちこちに出てくる場合などは、
その同じ処理を自作の関数にまとめるとメリットがある。
 
*オブジェクト形式マクロ
== 引数と返却値をもつ関数 ==
次の形式の前処理指令をオブジェクト形式マクロと呼ぶ。
<source lang=c>
#define 識別子 置換要素並び
//例 引数と返却値をもつ関数
</source>
#include <stdio.h>
defineの直後に記述してある識別子をマクロ名という。
オブジェクト形式マクロは、
これ以降のマクロ名を置換要素並びで置き換える。
 
*関数形式マクロ
double calc(double radius)//「calc関数の定義」
次の形式の前処理指令を関数形式マクロと呼ぶ。
{
<source lang=c>
return 3.14*radius*radius;
#define 識別子(識別子並び) 置換要素並び
}
 
int main(void)
{
double radius, area;
printf("円の半径を入力してください。:");
scanf("%lf", &radius);
area=calc(radius);//「calc関数の呼び出し」
printf("円の面積は%fです。\n",area);
}
</source>
識別子並びは省略可能で、仮引数を指定し、個々の仮引数は「,」で区切り、最後に省略記号「...」を指定してもよい。
この例では、自作のcalc関数を用いて、円の半径から円の面積を計算している。
関数形式マクロは、
このcalc関数は引数と返却値をもつ関数である。
これ以降のマクロ名とそれに続く「(」からそれに対応する「)」までを、
「calc関数の呼び出し」のところのradiusを実引数と呼ぶ。
置換要素並びで置き換える(マクロ呼出し)。
「calc関数の定義」のところのradiusを仮引数と呼ぶ。
このプログラムでは、
「calc関数の呼び出し」で、まずmain関数のradiusが実引数としてcalc関数に渡され、
その値がcalc関数の仮引数のradiusにコピーされ、
それから、計算結果が返却値として返され、
その値が変数areaに代入されている。
 
=== 実引数置換 ===
関数を呼び出すとき、
<ref>『JISX3010:2003』p.116「6.10.3.1 実引数置換」</ref>
引数と制御が戻るべきアドレス(リターンアドレス)がスタックと呼ばれる領域に格納される。
また、返却値がレジスタと呼ばれる領域に格納される。<ref>矢沢久雄、原田英生『日経 BP パソコンベストムック C言語とC++がわかる本』日経ソフトウェア、2013年5月15日発行、096項</ref>
 
実引数置換とは、関数形式マクロの実引数を識別した後行われ、
== 関数原型 ==
実引数の中に含まれるすべてのマクロの展開後、
<ref>『JISX3010:2003』p.51「6.5.2.2 関数呼び出し」</ref>
置換要素並びの中の仮引数を対応する実引数で置き換える。
関数原型(関数プロトタイプ)とは、関数の宣言である。
ただし、#前処理字句または##前処理字句が前にある仮引数と、##前処理字句が後に続く仮引数とは除く。
ある関数が使われる前に、その関数の識別子、引数、返却値を示し、その関数が使えるようにする。
実引原型を使うと置換の前に引数の個数とデータ型がチェッ前処理字句列を完全にマされロ置き換えする。
このとき、実引数ごとに、その前処理字句列が、現在の前処理ファイルの残りとなっているものとみなして処理する。
つまり、他の前処理字句列が存在しないかのように扱われる。
 
置換要素並びの中に現れる識別子__VA_ARGS__は、それが一つの仮引数であるかのように扱われなければならない。
関数原型を使わなくても、関数が使われる前に、その関数の定義を書くことで、その関数を使うことができる。
それを、可変個数の実引数が形成する前処理字句列で置き換える。
だが、ソースコードが大規模になるとそれも難しくなる。
また、関数原型を使わず、関数が使われる前にその関数の定義を書かなかった場合、
返却値は暗黙のうちint型とされ、引数のデータ型もチェックされない。
 
=== #演算子 ===
関数原型の記述は次のようになっている。
<ref>『JISX3010:2003』p.116「6.10.3.2 #演算子」</ref>
<source lang=c>
返却値のデータ型 関数の識別子(引数のリスト);
</source>
引数のリストの記述は次のようになっている。
<source lang=c>
引数のデータ型 引数の識別子
</source>
引数のリストには、引数がない場合はvoidのみを書く。
複数の引数がある場合、コンマで区切る。
 
 #演算子は、文字列化演算子と呼ばれ、
関数原型の引数の有効範囲は、関数宣言子の最後で終了する(関数原型有効範囲)。
関数形式マクロの置換要素並びの中の仮引数の直前に付けることができ、#前処理字句と仮引数を、実引数を「"」で囲んだ単純文字列リテラルで置き換える。
<ref>『JISX3010:2003』p.21「6.2.1 識別子の有効範囲」</ref>
その際、「"」文字及び「\」文字の前に、「\」文字が挿入される。
 
=== ##演算子 ===
<source lang=c>
<ref>『JISX3010:2003』p.116「6.10.3.3 ##演算子」</ref>
//例 関数原型の使用例
#include <stdio.h>
 
 ##演算子は、トークン連結演算子と呼ばれ、
double function(double a, double b);//関数原型
オブジェクト形式マクロ又は関数形式マクロの置換要素並びの中で使われ、
その直前にある字句とその直後にある字句を連結する。
関数形式マクロの置換要素並びの中で、
仮引数の直前又は直後に##前処理字句がある場合、
その仮引数を対応する実引数で置き換える。
 
=== 再走査と再置き換え ===
int main(void)
<ref>『JISX3010:2003』p.117「6.10.3.4 再走査と再置き換え」</ref>
{
printf("%f", function(0.12, 3.45));
}
 
実引数置換、#演算子及び##演算子の処理、プレースマーカー前処理字句の削除を行った後、
//2つの浮動小数点数の和を求めるfunction関数
さらに置き換えるべきマクロ名があるかどうかを調べるために、
//関数原型があるおかげで、
ソースファイル上のその後のすべての前処理字句とともにその結果の前処理字句を再走査する。
//関数の使用の後に関数の定義を書くことができる。
double function(double a, double b)
{
return a+b;
}
</source>
 
現在置き換え中のマクロの名前を置換要素並びのこの走査中に検出した場合や
== 再帰 ==
入れ子になった置き換えで現在置き換え中のマクロの名前を検出した場合は、
再帰とは、ある関数がその関数自身を呼び出すことである。
置き換えは行わない。
再帰に向いた計算に再帰を使うと、ソースコードを簡潔に書ける場合がある。
 
完全にマクロ置き換えした結果の前処理字句列は、
ある関数がその関数自身を呼び出すたびに、
前処理指令の形をしていたとしても、
引数と制御が戻るべきアドレス(リターンアドレス)が、
前処理指令として処理することはない。
スタックと呼ばれる領域に格納される(プッシュ)。
また、ローカル変数もスタックと呼ばれる領域に格納されている。
関数の処理が終わるたびに、
スタックに最後に格納したデータを取り出して(ポップ)、
関数を呼び出したときの状態を復元し、
処理を続ける。<ref>矢沢久雄、原田英生『日経 BP パソコンベストムック C言語とC++がわかる本』日経ソフトウェア、2013年5月15日発行、112項</ref>
 
=== マクロ定義の有効範囲 ===
再帰を行うには、その関数がリエントラントである必要がある。
<ref>『JISX3010:2003』p.117「6.10.3.5 マクロ定義の有効範囲」</ref>
リエントラントであるためには、使用する変数を共有しないように気を付ける必要がある。<ref>『再入可能とは 「リエントラント」 (reentrant) さいにゅうかのう: - IT用語辞典バイナリ』http://www.sophia-it.com/content/%E5%86%8D%E5%85%A5%E5%8F%AF%E8%83%BD</ref>
<source lang=c>
//例 再帰を使った階乗の計算
#include <stdio.h>
 
マクロ定義の有効範囲は、そのマクロ定義から、対応する#undef指令を検出するまで又は前処理翻訳単位の最後までである。
int factorial(int n);
 
int main(void)
{
int i;
printf("整数を入力してください:");
scanf("%d", &i);
printf("%dの階乗は%dです。", i, factorial(i));
}
 
int factorial(int n)
{
if(n==0)return 1;
return factorial(n-1)*n;
}
</source>
この例では再帰を使って、入力された整数の階乗を計算している。
3を入力した場合、処理の流れは以下のようになる。
 
マクロ定義を無効にするには、次のように記述する。
<source lang=c>
#undef 識別子
factorial(3)が呼ばれ、
factorial(3)が実行され、factorial(2)が呼ばれ、
factorial(2)が実行され、factorial(1)が呼ばれ、
factorial(1)が実行され、factorial(0)が呼ばれ、
factorial(0)が実行され、1が返され、
factorial(1)に戻り、1*1が返され、
factorial(2)に戻り、1*1*2が返され、
factorial(3)に戻り、1*1*2*3が返される。
</source>
識別子で無効にしたいマクロ名を指定する。
 
== 行制御 ==
== 値渡しと参照渡し ==
<ref>『JISX3010:2003』p.120「6.10.4 行制御」</ref>
aとbとの値を入れ替えるswap関数を考える。
<source lang=c>
//例 誤ったswap関数
#include "stdio.h"
 
行制御とは、この指令の次のソース行の行番号を指定する前処理指令である。
void swap(int a, int b){
行制御の記述は、次の2通りがある。
int x;
x=a;
a=b;
b=x;
}
 
int main(){
int a=1, b=2;
printf("swap前のa=%d, b=%d\n", a, b);
swap(a, b);
printf("swap後のa=%d, b=%d\n", a, b);
}
</source>
 
呼び出し先のvoid swap(int a, int b){のa, bを仮引数と呼ぶ。
呼び出し元のswap(a, b);のa, bを実引数と呼ぶ。
 
この例は意図通りに動作しない。何故なら実引数の値が仮引数にコピーされたためである。
<source lang=c>
#line 数字列
swap前のa=1, b=2
swap後のa=1, b=2
</source>
この指令の次のソース行の行番号が、数字列で指定された行番号となる。
と表示される。
数字列は1以上2147483647以下の10進整数でなければならない。
 
<source lang=c>
#line 数字列 "s文字列"
//例 正しいswap関数
#include "stdio.h"
 
void swap(int *a, int *b){
int x;
x=*a;
*a=*b;
*b=x;
}
 
int main(){
int a=1, b=2;
printf("swap前のa=%d, b=%d\n", a, b);
swap(&a, &b);
printf("swap後のa=%d, b=%d\n", a, b);
}
</source>
この指令は、同様に行番号を設定し、s文字列でソースファイル名を置き換える。
 
また、次の形式の行制御の前処理指令もある。
この例は意図通りに動作する。何故なら、実引数のアドレスが仮引数にコピーされたためである。
<source lang=c>
#line 前処理字句列
swap前のa=1, b=2
swap後のa=2, b=1
</source>
この形式の前処理字句列は、
と表示される。
マクロ置き換えで、上の2通りの形式のいずれかと一致せねばならず、
一致した形式の規則に従って処理する。
 
== エラー指令 ==
例6のように実引数の値を仮引数にコピーすることを''値渡し''と呼ぶ。
<ref>『JISX3010:2003』p.121「6.10.5 エラー指令」</ref>
例7のように実引数のアドレスを仮引数にコピーすることを''参照渡し''と呼ぶ。
 
== 関数に複数の返却値を持たせる ==
関数に複数の返却値を持たせたいとき、以下の2つの方法がある。
 
ポインタを使って、参照渡しの引数を、
返却値として用いる方法がある。
 
また、返却値のデータ型に構造体を使って、
その構造体で複数の返却値を表現する方法もある。
構造体については、[[C言語/構造体・共用体]]を参照せよ。
 
エラー指令とは、処理系に対し、
指定された前処理字句の列を含む診断メッセージを出力することを指示する前処理指令である。
エラー指令の記述は次のようになっている。
<source lang=c>
#error 前処理字句列
//例 関数に複数の返却値を持たせる。
#include <stdio.h>
 
int function(int *a, int *b)
{
*a=1234;
*b=5678;
}
 
int main(void)
{
int i,j;
function(&i, &j);
printf("iの値は%d、jの値は%d。", i, j);
}
</source>
前処理字句列で出力する診断メッセージを指示する。
 
== プラグマ指令 ==
== 関数へのポインタ ==
<ref>『JISX3010:2003』p.121「6.10.6 プラグマ指令」</ref>
関数へのポインタとは、
ある関数のメモリアドレスを格納し、
その関数に間接的にアクセスする方法である。
関数へのポインタは、
次のような場合に使われる。
ひとつは、関数を呼び出す際に、
関数へのポインタを引数として渡し、
呼び出した関数の内部で、
関数へのポインタが指す関数を実行する場合。
もうひとつは、関数へのポインタの配列をつくり、
if文や、switch文で関数を呼び出すのをやめ、
コードを単純にする場合。
 
プラグマ指令とは、処理系に対し処理系定義の方法で動作することを指示する前処理指令である。
関数へのポインタの宣言の記述は次のようになっている。
処理系が認識できないプラグマ指令は、無視する。
プラグマ指令の記述は次のようになっている。
<source lang=c>
#pragma 前処理字句列
返却値のデータ型 (*関数へのポインタの識別子)(引数のリスト):
</source>
この宣言では、
代入する関数と同じ返却値のデータ型と引数のリストを指定する必要がある。
また、演算子の優先順位のため、
「*関数へのポインタの識別子」を囲う「()」を省略はできない。
 
詳しくはコンパイラのヘルプを参照せよ。
関数のメモリアドレスを関数へのポインタに格納する記述は次のようになっている。
<source lang=c>
関数へのポインタの識別子=関数の識別子;
</source>
関数の識別子の後ろに、「()」はいらないことに注意。
 
== 空指令 ==
関数へのポインタを使って、
<ref>『JISX3010:2003』p.121「6.10.7 空指令」</ref>
間接的に関数を呼び出すには、
次のように記述する。
<source lang=c>
(*関数の識別子)(引数のリスト)
</source>
 
空指令とは、何の効果もない前処理指令である。
空指令の記述は次のようになっている。
<source lang=c>
#
//例 関数へのポインタの引数
#include <stdio.h>
 
void func1()
{
printf("func1()が呼び出されました。\n");
}
 
void func2(void (*func)())
{
printf("func2()が呼び出されました。\n");
(*func)();
}
 
 
int main(void)
{
func2(func1);
}
</source>
 
== あらかじめ定義されたマクロ名 ==
<source lang=c>
<ref>『JISX3010:2003』p.121「6.10.8 あらかじめ定義されたマクロ名」</ref>
//例 関数へのポインタの配列
#include <stdio.h>
 
あらかじめ定義されたマクロ名がある。
int add(int a, int b)
そのマクロ名と意味は次のようになっている。
{
return a+b;
}
 
{|class="wikitable"
int sub(int a, int b)
!マクロ名!!意味
{
|-
return a-b;
|__DATE__||前処理翻訳単位の翻訳の日付("Mmm dd yyyy"の形式をもつ単純文字列リテラル)
}
|-
|__FILE__||ソースファイル名(単純文字列リテラル)
|-
|__LINE__||現在のソース行の行番号(整数定数)
|-
|__STDC__||整数定数1.規格合致処理系であることを示す。
|-
|__STDC_HOSTED__||処理系が規格合致ホスト処理系の場合、整数定数1。そうでない場合、整数定数0。
|-
|__STDC_VERSION__||整数定数199901L。
|-
|__TIME__||前処理翻訳単位の翻訳の時刻。("hh:mm:ss"の形式の単純文字列リテラル)
|-
|__STDC_IEC_559__||「IEC60559 浮動小数点演算」の規定に合致することを示すための整数定数1。
|-
|__STDC_IEC_559_COMPLEX__||「IEC60559 互換複素数演算」の規定に合致することを示すための整数定数1。
|-
|__STDC_ISO_10646__||型wchar_tの値が、ISO/IEC 10646で定義された文字の符号化表現をもつことを示すためのyyyymmLの形式の整数定数。
|-
|}
 
== プラグマ演算子 ==
int mul(int a, int b)
<ref>『JISX3010:2003』p.122「6.10.9 プラグマ演算子」</ref>
{
return a*b;
}
 
int div(int a, int b)
{
if(b==0){
printf("0で割ることはできません。\n");
return 0;
}else{
return a/b;
}
}
 
int main(void)
{
int i,j;
int arithmetic;
int (*func[])(int a, int b)={add, sub, mul, div};
printf("2つの整数をスペースで区切って入力してください。:");
scanf("%d %d", &i, &j);
printf("計算方法を入力してください(0=加法、1=減法、2=乗法、3=除法)。:");
scanf("%d", &arithmetic);
if(0<=arithmetic&&arithmetic<=3)
printf("答えは%d。\n", (*func[arithmetic])(i,j));
}
</source>
 
== inline ==
<ref>『JISX3010:2003』p.83「6.7.4 関数指定子」</ref>
 
関数指定子inlineは、関数の宣言だけで使用できる。
関数指定子inlineは、その関数の呼び出しを可能な限り速くすることを示唆する。
この示唆が効果をもつ程度は、処理系定義とする。
 
inline関数は、その関数を呼び出した部分に展開して直接埋め込む。
関数呼び出しにかかる処理を短縮することができるが、
コードを複数の部分に展開するためファイルサイズが大きくなる。
 
プラグマ演算子は、指定した文字列リテラルを文字列解除し、その結果をプラグマ指令の中の前処理字句列として実行する。
つまり、次の形式の指令は、その次の形式でも表現できる。
<source lang=c>
#pragma listing on "..\listing.dir"
//例 inline関数の使用例
_Pragma("listing on \"..\\listing.dir\"")
#include <stdio.h>
 
inline int function(int a, int b)
{
return a+b;
}
 
int main(void){
int r;
r=function(1,2);
}
</source>
 
510 ⟶ 284行目:
<references/>
 
[[Category:C言語|せんしよりしれい]]