if文
if文(イフぶん、英: if statement)は、プログラミング言語において、真理値に従って「もし条件Cが満たされるならば、Xを実行せよ」というような条件付き実行の「文」で、制御構造のひとつである。一般的にif文は「もし条件Cが満たされるならば、Xを実行せよ、さもなくばYを実行せよ」というように条件が満たされなかった場合の分岐もオプション(省略可能)として同時にサポートすることが多く、if-else文と呼ばれることもある。
具体的な構文はプログラミング言語によって異なるが一般的に、条件式と、条件式の評価結果の値が「真として扱うべき値」の場合に実行される「then節」と呼ばれる部分があり、「偽として扱うべき値」の場合に実行されるelse節と呼ばれる部分が付く場合もある。「もしAならばX、BならばY、それ以外はZ」というように複数の条件で分岐する場合、C言語のようにif-else文を入れ子にすることで疑似的にelse-if節をサポートする言語もあれば、真のelse-if節をサポートする言語もある。
then節とelse節が式になる「条件演算子」がある言語も多い。言語によってはifが文ではなく、条件演算子と同様の「if式」である言語もある。
真偽値
[編集]「真として(あるいは、偽として)扱うべき値」について詳説する。条件式の値が真理値をとるブーリアン型でなければならない言語もあるが、そのように限定していない言語もある。C言語にはそもそもブーリアン型が無くint
で代用しているが、条件式としては汎整数型のゼロ(0)の他、ヌルポインタや浮動小数点数型の 0.0 なども偽として扱われる。Rubyではnilとfalse以外は真として扱われる。JavaScriptにはtruthyとfalsyという用語があり、falseの他いくつかの値がfalsyで、その他の多くの値はtruthyである。比較的少数の偽になる値の他は、真、という言語が多いが、それと逆に、Dart言語(のproduction mode)のようにtrue以外は偽という言語もある(checked modeではbool以外の型だとエラー)。
構文など
[編集]以下ではいくつかの言語やソフトウェアにおける、if文またはそれに類似したものの構文(syntax)などについて述べる。
C
[編集]if文の条件式はスカラー型の式である(構造体や共用体のような複合型の式は使えない)[1]。C99よりも前の規格では真理値のみを扱うための型は無かったため、従来からint
型で代用されてきた。整数値0に等しい値(あるいは暗黙変換によって0に等しくなる値)は偽、他の値は真として扱われる。真を代表して表すための値は整数値1である(比較式の結果はint
型であり、0または1となることが保証されている[2])。then節とelse節には、1個の文か、{ }
で囲まれる複文(ブロック)を書く。
真の時だけ実行するとき
if (条件式)
then節
真と偽の両方に振り分けるとき
if (条件式)
then節
else
else節
複数の条件で分岐するときは以下のように書くことができる。
int x = f();
if (x == 1) {
/* x の値が 1 のとき */
}
else if (x == 2) {
/* x の値が 2 のとき */
}
else {
/* x の値が 1 でもなく 2 でもないとき */
}
実際には以下のようにif-elseの入れ子となっているだけである。
int x = f();
if (x == 1) {
/* x の値が 1 のとき */
}
else
if (x == 2) {
/* x の値が 2 のとき */
}
else {
/* x の値が 1 でもなく 2 でもないとき */
}
上記のコードはswitch文で書くこともできるが、比較対象が整数定数でない場合や、1つの条件式にAND条件やOR条件を組み合わせる場合はif文を使う必要がある。ただしあまりに多数の条件分岐をif-elseで記述すると、入れ子階層の上限に達してしまい、コンパイル不能となることもある[3]。C99の規格で保証されている入れ子階層の数は127までである[4]。多数のcaseラベルを含むswitch文はコンパイラによってテーブルジャンプに置き換えられることもあり、その最適化が施された場合は最初のラベルに該当するケースと最後のラベルに該当するケースでパフォーマンスに差はない。一方、if文における最後の分岐に該当する場合、それ以前の分岐における条件式をすべて実行することになり、分岐の数に応じてパフォーマンスが悪化する。
Cでは代入は文ではなく式であり値を返すため、以下のように条件式として代入式を使うこともできる。
int x;
if (x = f()) {
/* x の値が 0 でないとき */
}
else {
/* x の値が 0 のとき */
}
しかし不注意なプログラマは比較演算子の==
と間違えて=
と記述してしまうこともあるため、このような書き方をすると警告を出す仕様になっているコンパイラも多い[5][6]。
C++
[編集]C++はCから発展した言語であり、構文なども概ね上位互換だが、細かな仕様において互換性のない部分も多い。
値としてfalse
(0) またはtrue
(1) のみを取りうるbool
型を持っており、組み込みの型に対する比較式の結果はbool
型となる[7]。if文の条件式はこのbool
型に暗黙的に変換可能な式を受け付ける。Cとの互換性のため、bool
型は整数型の一種であり、その他の整数型や浮動小数点数型、ポインタ型などの値は、条件式の文脈においてbool
型に暗黙変換可能となっている。そのため、このような型T
への暗黙変換演算子オーバーロードoperator T()
を持つユーザー定義型のインスタンスであれば、if文の条件式として直接使うことも可能である。
struct MyStruct {
std::string name;
operator size_t() const { return name.size(); }
};
MyStruct obj = {"abc"};
if (obj) {
// obj.name が空文字列でないとき。
}
size_t size = obj; // 暗黙の型変換があらゆる場面で発動する。
ただしこのような暗黙変換は思わぬ場面で発動することもあり、問題を引き起こすことが多い。安全のため、C++11では、明示的な型変換演算子オーバーロードを定義できるexplicit operator T()
の構文がサポートされた[8]。T
がbool
の場合、条件式の文脈においては暗黙変換可能となる。
struct MyStruct {
std::string name;
explicit operator bool() const { return !name.empty(); }
};
MyStruct obj = {"abc"};
if (obj) {
// obj.name が空文字列でないとき。
}
bool b = static_cast<bool>(obj); // 条件式の文脈でない場合、型変換には明示的なキャストが必要。
C++ではif文の条件式で変数を宣言することも可能である。変数の生存期間はそのif-else文を抜けるまでとなる。
if (int x = f()) {
// x の値が 0 でないとき。
}
else {
// x の値が 0 のとき。
}
C++17では、if文における初期化と条件式を分離した構文が使えるようになった[9]。
if (int x = f(); x == 123) {
// x の値が 123 のとき。
}
else {
// x の値が 123 でないとき。
}
Java
[編集]Javaのif文は条件式としてboolean
型のみを許可する。boolean
型の変数への代入またはプリミティブラッパークラスjava.lang.Boolean
型の変数への代入を除き、代入式を記述することはできない。
C++のようにif文の条件式の中で変数を宣言することはできないが、Java 16では、instanceof
演算子を使ったパターンマッチングの構文をサポートするようになった[10]。
Object obj = getSomeObject();
if (obj instanceof String str) {
// obj の型が String のとき。
System.out.println("String length = " + str.length());
}
else {
// obj の型が String でないとき。
}
上記は下記と等価である。
Object obj = getSomeObject();
if (obj instanceof String) {
// obj の型が String のとき。
String str = (String) obj;
System.out.println("String length = " + str.length());
}
else {
// obj の型が String でないとき。
}
C#
[編集]C#はJavaとよく似ており、if文は条件式としてbool
型のみを許可する。bool
型の変数への代入またはbool
への暗黙変換演算子static implicit operator bool()
などをユーザー定義した型の変数への代入を除き、代入式を記述することはできない。
C# 7ではis
演算子が拡張され、型パターンなどの構文が使えるようになった[11][12]。
object obj = GetSomeObject();
if (obj is string str) {
// obj の型が string のとき。
System.Console.WriteLine("String length = " + str.Length);
}
else {
// obj の型が string でないとき。
}
// 変数 str は if-else 文を抜けた後も使用できるが、未割り当て(未初期化)となる。
Lisp
[編集]Lispでは、ifは関数のような見掛けだが実引数が評価されない特殊形式(マクロ)である。真偽値は、nil
という名前や中身の無いカッコ ()
で表現される空リストが偽として扱われ、他の値は真として扱われる。then節とelse節のどちらも式である。
真の時だけ実行するとき
(if 条件式 then節)
真と偽の両方に振り分けるとき
(if 条件式 then節 else節)
Lispにはcondという、同等の機能を実現できる特殊形式もある。仕様や実装によっては、ifがcondに展開されるマクロのこともあるし、condがifに展開されるマクロのこともある。
Pascal
[編集]then節とelse節には、1個の文か、begin
- end
で囲まれる複文を書く。
真の時だけ実行するとき
if 条件式 then
then節
真と偽の両方に振り分けるとき
if 条件式 then
then節
else
else節
Ada
[編集]Adaでは条件式の型はBoolean
(もしくはBoolean
の派生型)でなければならない。これはJava等も同様である。
真の時だけ実行するとき
if 条件式 then
then節
end if;
真と偽で実行文を変えるとき
if 条件式 then
then節
else
else節
end if;
Perlの場合
[編集]真の時だけ実行するとき
真文 if 条件文
偽の時だけ実行するとき
偽文 unless 条件文
また、C言語風の記述法も可能である。
真の時だけ実行するとき
if(条件文) {
真文
}
真と偽で実行文を変えるとき
if(条件文) {
真文
} else {
偽文
}
Rubyの場合
[編集]Rubyのifは厳密に言えばif式であり、条件が成立した方の節で最後に評価された式の値を返す。
真の時だけ実行するとき
if 条件式 (then)
真文
end
真と偽で実行文を変えるとき
if 条件文 (then)
真文
else
偽文
end
BASICの場合
[編集]真の時だけ実行するとき
IF 条件式 THEN 真文
真と偽で実行文を変えるとき
IF 条件式 THEN 真文 ELSE 偽文
真文・偽文が1行で書ききれない場合はgoto文が併用される。
Visual Basicの場合
[編集]Visual Basic (VB)、Visual Basic for Applications (VBA)、Visual Basic .NET (VB.NET) は複文にも対応している。
真の時だけ実行するとき
If 条件式 Then
真文
End If
真と偽で実行文を変えるとき
If 条件式 Then
真文
Else
偽文
End If
真文・偽文が1行だけの場合にはBASICと同様の書き方(単一行構文)も可能である[13][14]。
表計算ソフトウェア
[編集]表計算ソフトウェアのMicrosoft Excel、OpenOffice.org Calc、LibreOffice Calc、Google スプレッドシートなどでは、ワークシート関数のひとつとしてIF
関数をサポートしている。
Excelの場合は以下の構文である[15]。
IF(テストする条件, 真の場合の値, 偽の場合の値)
関数という性質上、「偽の場合は何も返さない(何も実行しない)」というようなことはできないが、偽の場合は0
や空文字列""
を返すといった形で記述できる。
LibreOffice Calcの場合は以下の構文である[16]。
IF(テストする条件; 真の場合の値; 偽の場合の値)
真の場合の値や偽の場合の値を空にした場合、0とみなされる。
Googleスプレッドシートの場合は以下の構文である[17]。
IF(テストする条件, 真の場合の値, 偽の場合の値)
偽の場合の値(FALSE
値)を省略することができ、デフォルトは空欄(ブランク)となる。
IFS関数
[編集]LibreOffice Calc 5.2以降[18]およびExcel 2019以降(Office 365含む)[19]ではIFS
関数をサポートする。
IFS(条件式1, 真の場合1, 条件式2, 真の場合2, ..., 条件式127, 真の場合127)
条件式は先に評価されるべきものから並べる必要がある。IF関数の入れ子構造と処理は同一であるが、簡潔に記述できる。
LibreOffice CalcとExcelのIFS
関数では、最大127個の条件をテストすることができる。ただし、IF
またはIFS
であまりにも多くの条件をネストすることは推奨されていない。複数の条件は正確な順序で入力する必要があり、かつ、構築、テスト、更新を行うのが大変難しくなる場合があるからである[19]。
IFS
関数はGoogleスプレッドシートでもサポートされている[20]。
FORTRAN
[編集]以下は、Fortran77以降の、論理IF文の場合である。1行のみの場合
if(条件式) 真文
複数行にまたがる場合
if(条件式1) then
条件式1が真の場合ここから
ここまでのプログラムが実行される(複数行)
else if(条件式2) then
条件式2が真の場合ただしすでに条件式1が成り立っている場合は除くここから
ここまでのプログラムが実行される(複数行)
else
すべてのなかのいずれの条件にも当てはまらない場合ここから
ここまでのプログラムが実行される(複数行)
end if
Forthの場合
[編集]真の時だけ実行するとき
条件式 IF 真文 THEN
偽の時だけ実行するとき
条件式 NIF 偽文 THEN
真と偽で実行文を変えるとき
条件式 IF 真文 ELSE 偽文 THEN
または
条件式 NIF 偽文 ELSE 真文 THEN
ひまわりの場合
[編集]真の時だけ実行するとき
もし、{条件式}ならば、( {処理} )
真と偽で実行文を変えるとき
もし、{条件式}ならば、( {処理} ) 違ったら、( {処理} )
HSPの場合
[編集]真の時だけ実行するとき
if 条件式 : 真文
真と偽で実行文を変えるとき
if 条件式 : 真文 : else : 偽文
また、Cのようにブレイスを用いることもできる。
if 条件式 { 真文 } else { 偽文 }
プログラム例
[編集]特に断りがない場合na
とnb
の大きい方をnc
に代入という意味である。
Cでの例
[編集]if (na > nb) {
nc = na;
} else {
nc = nb;
}
nc = (na > nb) ? na : nb
としても同じ事ができる。
Common Lisp での例
[編集](if (> na nb)
(setq nc na)
(setq nc nb))
Common Lispでは文ではなく式であるため、
(setq nc (if (> na nb) na nb))
と書くこともできる。
Pascalでの例
[編集]if na > nb then nc := na else nc := nb
R言語での例
[編集]nc <- ifelse(na > nb, na, nb)
FORTRANの例
[編集]if(a.eq.b) c=5
上記の記述ではa=b
の場合c=5
になる簡単なプログラム例である。
if(a.eq.100) then
b=30
else if(a.eq.80) then
b=25
else
b=20
end if
上記の記述ではa=100
の場合はb=30
となり,a=80
の場合はb=25
,その他の場合はb=20
となるプログラム例である。
論理積・論理和による擬似的なIf文
[編集]仮に &&
を論理積を表す演算子として、
左辺 && 右辺
という論理式で、左辺が真にならなければ右辺を評価しない言語(短絡評価)では、これを
If (左辺) { 右辺 }
と等価とみなすことができる。つまり左辺が条件文で、右辺が真文となるわけである。
同様に ||
を論理和を表す演算子だとすると、
左辺 || 右辺
は
If (Not 左辺) { 右辺 }
と等価となり、左辺が偽のときだけ右辺が実行される。
たとえばMS-DOSやWindowsのバッチファイルでは条件付き処理シンボル&&
と||
がある[21]。
CHDIR C:\HOGE || ECHO フォルダがみつかりません
(もしCHDIRコマンドが失敗したら、ECHOコマンドが実行される)
JavaScriptなど言語によっては、このように論理積演算や論理和演算を擬似的なIf文にできることがある。
脚注
[編集]- ^ ISO/IEC 9899:1999 §6.8.4.1 The if statement
- ^ 比較演算子 - cppreference.com (C)
- ^ Fatal Error C1061 | Microsoft Learn
- ^ ISO/IEC 9899:1999 §5.2.4.1 Translation limits
- ^ Compiler Warning (level 4) C4706 | Microsoft Learn
- ^ Diagnostic flags in Clang — Clang git documentation
- ^ 比較演算子 - cppreference.com (C++)
- ^ 明示的な型変換演算子のオーバーロード - cpprefjp C++日本語リファレンス
- ^ if文とswitch文の条件式と初期化を分離 - cpprefjp C++日本語リファレンス
- ^ Java言語更新 - instanceofのパターン・マッチング | Java SE 16
- ^ Dissecting the pattern matching in C# 7 - Developer Support
- ^ 第3回 型による分岐の改良:特集:C# 7の新機能詳説(2/2 ページ) - @IT
- ^ Using If...Then...Else statements (VBA) | Microsoft Learn
- ^ If...Then...Else ステートメント - Visual Basic | Microsoft Learn
- ^ IF 関数 - Microsoft サポート
- ^ Logical Functions | LibreOffice Help
- ^ IF - Google ドキュメント エディタ ヘルプ
- ^ IFS function | LibreOffice Help
- ^ a b IFS 関数 - Microsoft サポート
- ^ IFS - Google ドキュメント エディタ ヘルプ
- ^ Command shell overview | Microsoft Learn