「C言語/関数」の版間の差分

削除された内容 追加された内容
Ef3 (トーク | 投稿記録)
→‎swap関数: 外部のスコープのインスタンスがより内側のスコープで同じ識別子を持つインスタンスによって隠されてしまう事を、シャドーイング(Shadowing)と呼ぶ。s/#include "stdio.h"/#include <stdio.h>/、{{コラム|新たに変数を用意せず2つの変数を入れ替える }}
タグ: 2017年版ソースエディター
Ef3 (トーク | 投稿記録)
cleanup
タグ: 2017年版ソースエディター
1 行
== 関数の基本 ==
C言語のプログラムは全て1つ以上の「関数」(かんすう)と呼ばれる処理のかたまとまりから構成されます
 
関数を用いて、いくつかの文をブロックでまとめることができます。「main関数」も関数であり、「printf」や「scanf」なども関数であるが、それとは別に、ユーザーがいくつかの処理をまとめて「関数」として定義できます
 
C言語でいう、ユーザー定義する「関数」は、よそのプログラム言語でいう「サブルーチン」のような性質がある(ただし、けっして、完全に「値を返すことができるかが関数とサブルルーチン」とC言語関数は同じでは大き。相違点も存在するが、説明が長くなるの後述)。
 
関数を用いることによって、同じ処理をまとめて書くことができ、以後その関数を呼び出すだけでまとめられた処理が実行できるようになる。
 
 
{{コラム|Visual Studio で、デバッグ セッションの終了時にコンソールが閉じてしまう場合|
Visual Studio で、デバッグ セッションの終了時にコンソールが閉じてしまう場合は、
: [ツール] -> [オプション] -> [デバッグ] -> [デバッグの停止時に自動的にコンソールを閉じる]
を無効にします。
}}
=== 関数の定義 ===
ユーザーが自分で定義する関数について、記法の例を表します。
 
//; 例 2つの整数を引数にとりその和を返却する関数
: <syntaxhighlight lang="C">
//例 2つの整数を引数にとりその和を返却する関数
int function(int a, int b)
{
return a + b;
}
</syntaxhighlight>
 
上記コードの「function」の部分が、その関数の名前であり、プログラマーが半角と _ なら自由に関数に名前をつけられます(ただし「if」などのキーワードや「printf」などの既存の用語ライブラリ関数名禁止なのが普通使用できません)。「function」でなくても「kansuumyFunc」などでも構いません。
 
以下、特にことわらないかぎり、ユーザーが定義した関数を、単に「関数」と省略する。main関数やprintfなども「関数」と省略する場合があるのでりますが読者は文脈から判断のユーザーが定義したこと以外に違いはありません
 
関数を呼び出す際、関数の 呼び出し元(仮に「親」と呼ぼう) から 呼び出し先関数(仮に「子」と呼ぼう)へ情報を渡すことができ、この渡され情報のことを'''引数'''(かりひきすう、argument)''parameter'')、渡した情報のことを'''実引数'''(じつひきすう、''argument'')と呼びます
 
関数の定義の記述は次のようになっている。
 
; 開式
: <syntaxhighlight lang="C">
返却値のデータ型 関数名 ( 引数の型と引数名リスト )
{
/*いくつかの文*/
35 ⟶ 39行目:
</syntaxhighlight>
 
関数名とはその関数を他の関数と区別するために付ける名前のことで、関数名に使えるのは半角英数、「_(下線)」である。ただし、先頭は非数字でなければならない。
多バイト文字を使用できるかはコンパイラ言語処理系によります
関数名に使えるのは半角英数、「_(下線)」である。
関数は他の関数の中で呼び出すことができます
ただし、先頭は非数字でなければならない。
多バイト文字を使用できるかはコンパイラによる。
関数は他の関数の中で呼び出すことができる。
 
また、引数は、省略できる場合がある。つまり、
 
また、引数は省略できる場合がありますつまり、
<syntaxhighlight lang="C">
返却値のデータ型 関数名()
49 ⟶ 50行目:
}
</syntaxhighlight>
のように関数を記述する場合もある<ref>引数の省略はC23で廃止予定で、voidを明示する必要があります。</ref>。
 
のように関数を記述する場合もある。
 
=== 関数の呼び出し ===
59 行
int function(int a, int b)
{
return a + b;
}
 
int main(void){
int r;
r = function(1, 2);//rには1と2との和である3が代入されます
}
</syntaxhighlight>
 
関数の定義側で書かれた引数のことを'''仮引数'''(かりひきすう、parameter)''parameter'')という。
 
いっぽう、関数の呼び出し側で書かれた引数のことを'''実引数'''(じつひきすう、''argument'')という。
 
関数の定義側で書かれた引数のことを'''仮引数'''(かりひきすう、parameter)という。
 
いっぽう、関数の呼び出し側で書かれた引数のことを'''実引数'''(じつひきすう)という。
 
----
複数の仮引数を持つ場合、「,(コンマ)」で区切る。仮引数を持たない場合、何も void をかないきます
 
; 仮引数
仮引数の記述は次のようになっている。
: <syntaxhighlight lang="C">
仮引数のデータ型 仮引数名
</syntaxhighlight>
84 ⟶ 82行目:
 
----
任意個数の実引数について、実引数を持たない場合何も書かないきません
複数の実引数を持つ場合、「,(コンマ)」で区切る。
 
; 実引数
実引数の記述は次のようになっている。
: <syntaxhighlight lang="C">
関数名(任意個数の実引数);
</syntaxhighlight>
 
----
また、関数の呼び出し先から呼び出し元へ情報を渡すこともでき、この情報を返却値と呼びます
返却値のデータ型で返却値の有無や種類を決定すします
任意個数の仮引数で仮引数の数や種類を決定すします
 
----
この例では、function関数の実引数である1,2が、function関数の仮引数であるa,bにコピーされ、a+bがfunction関数の返却値として返され、その値がrに代入されます。
function関数の仮引数であるa,bにコピーされ、
a+bがfunction関数の返却値として返され、
その値がrに代入される。
 
関数を呼び出すとき、
引数と制御が戻るべきアドレス(リターンアドレス)がスタックと呼ばれる領域に格納されます
また、返却値がレジスタと呼ばれる領域に格納されます。<ref>矢沢久雄、原田英生『日経 BP パソコンベストムック C言語とC++がわかる本』日経ソフトウェア、2013年5月15日発行、096項</ref>
 
 
125 ⟶ 120行目:
}
</syntaxhighlight>
この例では自作のHelloWorld関数を使って文字列を表示しています
このHelloWorld関数は引数と返却値をもたない関数である。
このプログラムでは、
137 ⟶ 132行目:
この例では関数を自作したメリットはないが、
同じ処理がソースコードのあちこちに出てくる場合などは、
その同じ処理を自作の関数にまとめるとメリットがあります
 
=== 引数と返却値をもつ関数 ===
158 ⟶ 153行目:
}
</syntaxhighlight>
この例では、自作のcalc関数を用いて、円の半径から円の面積を計算しています
このcalc関数は引数と返却値をもつ関数である。
「calc関数の呼び出し」のところのradiusを実引数と呼びます
「calc関数の定義」のところのradiusを仮引数と呼びます
このプログラムでは、
「calc関数の呼び出し」で、まずmain関数のradiusが実引数としてcalc関数に渡され、
172 ⟶ 167行目:
関数による通常の返却値の方法では、1つの値しか、呼び出し元関数に値を送れない
 
しかし、特殊な方法を使うことにより、呼び出しもとの関数に、複数の値を送ることができます
 
下記に述べるように、少なくとも以下の3つの方法があります
 
=== コラム ===
189 ⟶ 184行目:
「局所変数」(きょくしょ へんすう)とは、ある関数を呼び出したとき、呼び出された子サイド(呼び出し先)で、普通の方法で変数を変更しても、本体である親サイド(呼び出し元)の内容には変化を与えないという機能である。
 
C言語は局所変数の機能を実現するために、子サイドの関数を呼びだした時には、パソコンはまず、新しいアドレス内をコンパイラ言語処理系に与えており、それから親(呼び出し元)の引数(「実引数」という)のaの値とbの値とをそれぞれ新アドレスに代入するという方法により、子サイドの関数が呼び出された時にaやbの値をコピーしているのである。
 
このため、子(呼び出し先)の関数内(仮に関数fとする)で、通常の方法でaやbの値を変更しようが、親(呼び出し元)の関数(仮にgとする)で使われている同名の引数aとbのアドレスとは、親(呼び出し先)のアドレスとは別のアドレスなので、よって、子(呼び出し先)は、親(呼び出し元)の内容には、いっさい変化を与えないようにする事ができます
 
このようにして、C言語において、局所変数(「ローカル変数」)の機能が実現されます
 
このため、「return a;」のような返却値についても、ある関数内で変数が計算結果でa=6となった場合に、関数終了の返却値で「return a;」によって、aの数値を親(呼び出しもとの)関数に返却しても、返却値を受け取った側の親の関数は、単に「6」という数値を受け取ることになり、その数値6が変数aに由来する数値なのか、それとも変数bに由来する数値なのかは、受け取り側の親(呼び出し元)関数にとっては不明なのです。
201 ⟶ 196行目:
しかし、裏を返すと、C言語による「局所変数」機能の実現のための新アドレス準備・配当の仕組みのために、もし呼び出した子サイドの関数内で、親サイド(呼び出し元)の関数内にある値を変更しようとするとき、その実現がややこしくなってしまっている。
 
もし、子サイド(呼び出された)関数内で、親サイド(呼び出し元)の関数内にある同名の引数を変更したい場合には、下記の2つの方法があります
 
:static変数という、親子で共有する特殊な型の変数を宣言する方法。
216 ⟶ 211行目:
:そのため、呼び出し先の関数のポインタに格納されているアドレスの値は、大もとの親サイド(呼び出し元)で使っている引数のアドレスの値と同じ値である。
 
:なので、子サイド(呼び出し先)の関数のポインタにあるアドレス値をつかって、親サイド(呼び出し元)の引数のアドレスを操作できます
 
 
このようにして、アドレスやポインタを使うことにより、子サイド(呼び出し先)の関数内で操作をした場合に、親サイドも含む範囲(子サイドの関数外)にも影響を与える非局所的な操作をすることができます
}}
 
=== 「サブルーチン」との違い ===
C言語の関数のような「ローカル変数」のシステムは、よそのプログラム言語(ベーシックなど)の「サブルーチン」には無いシステムです。ベーシックのプログラム言語に、C言語でいう「ポインタ」システムが無いのは、そもそもローカル変数のシステムがベーシックには無いからです。
 
このC言語の「ローカル変数」システムこそが、C言語の「関数」システムの真骨頂(しんこっちょう)なのです。
231 ⟶ 226行目:
ベーシックでのサブルーチンの呼び出しは、単に「GOTO 100」みたいにGOTO文で行指定して指定先にジャンプするかわりに、行番号100にルーチン名を書いておいて、ルーチン名でジャンプ先を指定できるようにしたものに過ぎません。
 
しかし、C言語では、そもそもGOTO文のようなジャンプ方法が、忌避(きひ)されています。(いちおう、C言語にもGOTO文が存在するが、非推奨である)
 
 
246 ⟶ 241行目:
=== 「メソッド」 ===
「関数」というが、C言語の関数(function)は、数学の関数(function)とは、まったく違う。
 
これが、学習者の混乱の原因になるだろうとして、90年代ごろから、Visual C++などの言語では、C言語の関数とほぼ同じ意味で「メソッド」という用語が使われた。
 
Visual C++やC#などの言語でいう「メソッド」は、上述のC言語の「関数」と、ほぼ同じ機能、もしくは機能拡張したものである。
 
 
さらに2010年ごろから、function(ファンクション)に発音の似ている「アクション」の用語が一部のプログラム言語で使用されているが、しかし普及してない。
 
 
== static 変数とポインタの必要性 ==
262 ⟶ 249行目:
// static変数の使用例(コンパイルできる)
#include <stdio.h>
#include <stdlib.h> // 「続行するには何かキーを押してください . . .」を表示するのに必要。
 
void kansuufunc(void) {
int b = 0;
static int c = 0;
274 ⟶ 260行目:
 
int main(void) {
kansuufunc();
kansuufunc();
 
system("pause"); // 「続行するには何かキーを押してください . . .」の待機命令
 
return 0;
}
</syntaxhighlight>
286 ⟶ 268行目:
b = 1 ,c = 1
b = 1 ,c = 2
続行するには何かキーを押してください . . .
のようになる。
 
このように、static宣言された変数(上の例ではc)は、その関数が終わっても、数値が保存されます
 
また、初期化がされる(cに0が代入される)のは、最初に呼び出された1回だけである。
301 ⟶ 282行目:
// static宣言でエラーになる例1
#include <stdio.h>
#include <stdlib.h> // 「続行するには何かキーを押してください . . .」を表示するのに必要。
 
void kansuufunc(void) {
int b = 0;
static int c = 0;
311 ⟶ 291行目:
 
int main(void) {
kansuufunc();
printf("b = %d ,c = %d \n\n", b,
c); // このprintf関数がstatic宣言されたcにアクセスできない
 
kansuufunc();
printf("b = %d ,c = %d \n\n", b,
c); // このprintf関数がstatic宣言されたcにアクセスできない
 
system("pause"); // 「続行するには何かキーを押してください . . .」の待機命令
 
return 0;
}
</syntaxhighlight>
 
このように、static変数は、呼び出し元の関数は、存在を感知できない仕組みである。これによって、バグ発生時に原因箇所を特定しやすくしています
 
 
333 ⟶ 310行目:
// static宣言でエラーになる例2
#include <stdio.h>
#include <stdlib.h> // 「続行するには何かキーを押してください . . .」を表示するのに必要。
 
void kansuufunc(void) {
b = b + 1; // ここでエラー発生。bが何かを判断できない
c = c + 1;
344 ⟶ 320行目:
static int c = 0;
 
kansuufunc();
printf("b = %d ,c = %d \n\n", b,
c); // このprintf関数がstatic宣言されたcにアクセスできない
 
kansuufunc();
printf("b = %d ,c = %d \n\n", b,
c); // このprintf関数がstatic宣言されたcにアクセスできない
 
system("pause"); // 「続行するには何かキーを押してください . . .」の待機命令
 
return 0;
}
</syntaxhighlight>
360 ⟶ 332行目:
コンパイルの仕組みでは、上から順に部品を組み立てていくような仕組みなので、コード上方にある関数はコード下方にある関数の内容を知らない。
 
たとえ、コード下にある関数がmain関数であっても、その内容を知らないのであるりません。よって、上記のようなコードはコンパイルエラーになる。
 
かといって、<code>kansuufunc</code>をmain関数よりも下に書くと、今度はmain関数が、kansuufuncの内容を感知できないのであるません
たとえ、コード下にある関数がmain関数であっても、その内容を知らないのである。よって、上記のようなコードはコンパイルエラーになる。
 
かといって、<code>kansuu</code>をmain関数よりも下に書くと、今度はmain関数が、kansuuの内容を感知できないのである。
 
main関数といえども、main関数ブロックよりも下に書かれた内容を知ることはできないません
 
なので通常、main関数は一番下に書かれます
 
 
なお、最初の「例1」で紹介した例では、main関数で使用される変数bとcの上にある関数kansuufuncで定義されてるので、順序的には問題ないのですが、しかしC言語では、アクセスできないようになっています。
staticかどうかに関わらずアクセスできません。kansuu
funcの終了時に、その関数の型などの情報も消えるので、エラー例1のコードでは変数bとcの宣言内容を発見できず、利用できないません
 
 
398 ⟶ 371行目:
:しかも、その関数が終了してしまうので、ほかにも処理をその関数で続行したい場合に不便であるし、
:しかも、1つの数値しか送れない、
など、いろんな欠点があります
 
:また、returnはエラーの有無を判定結果を呼び出しもと関数に送信するときに使用することが、実務では多い。たとえば if文などで、想定外の事態がなければ0を返却するようにプログラムを記述して、いっぽう想定外があれば-1を返却する、などのように、返却値の値により、想定外の有無を送信することが、実務などで多い。
 
C言語の入門書で、「return a + b;」などのように、return文で計算結果を送信する記述が書かれてるのは、初心者の学習のための配慮(はいりょ)なのであり、じつは、あまり実務的ではないプログラムである。そもそも、わざわざ別関数で「a+b」を計算せずとも、最初からmain関数内で「a+b」を計算すれば済む。
 
また、入門書で、ポインタの章と関数の章が別々に書かれていることが多いのは、初心者のための配慮(はいりょ)なのであり、じつは、現実では、ポインタと関数を別々に考えるのは、あまり実用的ではないだろう。
422 ⟶ 395行目:
 
C言語では通常、変数をある関数ブロックの内部で宣言した際、その変数は、その関数ブロックの中でしか通用しない。
ある関数ブロックの内側でしか通用しない変数を'''ローカル変数'''と呼びます。いっぽう、(プログラム冒頭部(include文の直後など)などの)関数外で宣言した変数をグローバル変数と呼び、すべてのブロック内で通用する。
 
変数は宣言する場所によってローカル変数とグローバル変数とに分かれる。<ref>ローカル変数とグローバル変数という用語はよく使われるが、『JISX3010:2003』には出てこない。</ref>
435 ⟶ 408行目:
なので、通常、ある関数ブロックの中で宣言した変数は、すべてローカル変数である。たとえmain関数内で変数を定義をしても、その(main関数ないで宣言された)変数ですら、main関数内でしか通用しない。
 
もし、ある関数が、他の関数と値のやりとりをしたい場合は、関数の返却値(「返し値」、「戻り値」ともいう)を仲介して、値を別関数ブロックに送る必要があります
 
 
442 ⟶ 415行目:
 
* static
通常のローカル変数は、関数ブロックが終了するときに、変数の結果が消去されます。そして、再度関数を呼び出したときは、変数の宣言時に変数が作成されたり、あるいは関数ブロックに入るときに作成され、そしてまた、その関数ブロックが終了するときに、消去されます
 
この消去により、ある関数が別の関数の変数を書き換えないような仕組みになっている。しかし、このような関数では、もし、ある関数を複数回呼び出しても、前回使用した計算結果が消去されてしまっており、そのため、前回の計算結果を再利用するような作業が困難である。
449 ⟶ 422行目:
 
 
そこで、変数を再利用可能にすることのできる static スタティックという宣言があります。このstaticをつけると、たとえローカル変数でも、関数の終了時に、その変数の値が消去されずにメモリに残りつづけるようになるので、再度その関数を呼び出したときに、前回の(そのstaticのついた変数の)計算結果を再利用できます
 
「static」とは「静的」などと訳され、表現はいかめしいが、しかしstaticの実態は「関数が終わっても値を保管しとけ」程度の実態でしかない。
471 ⟶ 444行目:
 
* グローバル変数との違い
すべてのブロックからアクセスできる変数を「グローバル変数」と呼びます
 
C言語プログラミングでは一般に、コードファイルの冒頭の、どこの関数ブロック内でもない場所で変数宣言をすることにより、グローバル変数として宣言されたことになり、どこの関数からでもアクセスできます
 
しかし、その変数にアクセスできることと、各関数ブロックの実行時に領域を新規作成しないかは別のことである。
 
なので、グローバル変数といえども、各関数ブロックの計算結果を共有したい場合には、さらに宣言時に static を接頭辞につけて宣言する必要があります
 
 
484 ⟶ 457行目:
プログラムが終了したときに破壊される(静的記憶域期間)。<ref name="オブジェクトの記憶域期間"/>
また、グローバル変数は、定数式でのみ初期化することができ、
明示的に初期化しない場合、0で初期化されます
 
<pre>
496 ⟶ 469行目:
なので、他の関数と計算結果を共有する必要のない変数であれば、なるべく、個別の関数の内部で変数宣言をするのが良い。
 
いっぽう、他の関数と計算結果を共通したい場合、どうしてもグローバル変数を使わざるを得ない場合も多い。(もし、グローバル変数を用いないと、代わりにポインタを使わざるを得ない場合があります。)
 
これはつまり、そもそも、複数の関数どうしでの変数の共有は、なるべく、ひかえる必要があります、という事である。
 
 
505 ⟶ 478行目:
関数ブロックの内部で宣言された変数を「ローカル変数」と言う。
 
ローカル変数は、その関数が終わるときに消えるが、正確に言うと、そのローカル変数を宣言したブロックが終了するときに、そのローカル変数も消去されます。<ref>ウェブページ『関数内で寿命が尽きる変数 』 http://9cguide.appspot.com/12-01.html</ref>
 
ブロックとは、記号 { と } とで挟まれた処理単位である。
 
なので、関数内に、さらにブロックが入れ子になっていて、その入れ子内で宣言された変数は、その入れ子ブロックの終了時にその入れ子内にあった変数も消去されます
 
if文やfor文の{}もブロックと見なされるので、注意が必要である。<ref>ウェブページ『ロベールのC++教室 - 第68章 寿命 -』 http://www7b.biglobe.ne.jp/~robe/cpphtml/html01/cpp01068.html</ref>
520 ⟶ 493行目:
そのため、main関数以外の関数は、main関数よりも前で、宣言されていなければならない。
 
しかし、main関数から呼び出される関数は、mainよりも前で宣言さえされていれば、たとえ具体的な定義内容がmain関数のあとで書かれていても、その関数をmain関数から呼び出して使用できます。そのため、以下のように、main関数から呼び出される関数の存在の宣言だけを先に行うという記法が許されており、この記法では、呼び出し先の関数の具体的な定義内容はmain関数のあとで定義する事が許されている。
 
このような関数の宣言方法のことを「関数のプロトタイプ宣言」などという。
538 ⟶ 511行目:
//2つの浮動小数点数の和を求めるfunction関数
//関数原型があるおかげで、
//関数の使用の後に関数の定義を書くことができます
double function(double a, double b)
{
return a + b;
}
</syntaxhighlight>
547 ⟶ 520行目:
関数原型(関数プロトタイプ)とは、関数の宣言である。
ある関数が使われる前に、その関数名、引数、返却値を示し、その関数が使えるようにする。
関数原型を使うと、引数の個数とデータ型がチェックされます
 
関数原型を使わなくても、関数が使われる前に、その関数の定義を書くことで、その関数を使うことができます
だが、ソースコードが大規模になるとそれも難しくなる。
また、関数原型を使わず、関数が使われる前にその関数の定義を書かなかった場合、返却値は暗黙のうちint型とされ引数のデータ型もチェックされません(C11 では、関数宣言において型指定子を必須とし、暗黙的な型指定を禁じています)。
返却値は暗黙のうちint型とされ、引数のデータ型もチェックされない。
 
関数原型の記述は次のようになっている。
637 ⟶ 609行目:
</syntaxhighlight>
 
しかし、関数の返却値は、エラー判別などに利用される場合も多いので(関数によって「エラーなら返却値に 0 以外を返却する」などの仕様のある場合も多い)、よって上述の手法は、あまりオススメできないません
 
なお、strcpyは、文字列をコピーするための関数。strcpyを使うには、string.hのインクルードが必要である。
681 ⟶ 653行目:
たとえグローバル領域で「a」「b」と同名の変数があっても、swap関数内では同名なだけの別変数としての仮引数「a」「b」が新たに関数swap内では用意されてしまう。
 
:この様に、外部のスコープのインスタンスがより内側のスコープで同じ識別子を持つインスタンスによって隠されてしまう事を、シャドーイング(Shadowing)と呼びます
 
ユーザ定義関数内で変数の値を交換させるためには、一例として、下記のようにポインタを使ってmain関数の変数a,bを書き換える方法があります
 
<syntaxhighlight lang="C">
710 ⟶ 682行目:
swap後のa=2, b=1
</pre>
と表示されます
 
ポインタを使うと成功する理由は、main関数のローカル変数のアドレスが仮引数にコピーされたため、swap関数がmain関数のローカル変数a,bにアクセスできているからである(ポインタを介したswap関数内のa,bはもはやローカル変数だけでなくグローバル変数にもアクセスできる)。
717 ⟶ 689行目:
 
なお、
:ポインタを使わない例「誤ったswap関数」のように実引数の値を仮引数にコピーすることを''値渡し''と呼びます
:ポインタを使った例「正しいswap関数」のように実引数のアドレスを仮引数にコピーすることを''参照渡し''と呼びます
<ref>値渡しと参照渡しという用語はよく使われるが、『JISX3010:2003』には出てこない。</ref>
-->
 
----
ユーザ定義関数を何も書かずに全てmain関数に書く方法を使えば、ポインタを使わずとも交換できます
 
標準C言語では考える必要は無いが、別のプログラム言語だと、言語によってはポインタが標準設定では使用禁止されていたり(たとえばC#がそうである)、そもそもポインタに相当する機能の無い言語も考えられる<ref>最近は Fortran ですらポインタがあるのでポインタのない言語は非常に限られ、ポインタがなくてもVariant型に類する型がある場合が多い。</ref>。そのような場合でも、下記コードのようなアルゴリズムで、変数の交換は可能である。
863 ⟶ 835行目:
:(※ 動作確認: Windows の Visual Studio 2019でも2020年6月25日に動作を確認。 ただしC++なので <code> #include <iostream> </code> が必要。)
 
なおWindows版のclangはvisual studio のコンパイラ言語処理系を呼び出す方式であるので、試行を省略する。
 
 
915 ⟶ 887行目:
また、パソコンが発展してどんなに高性能になっても、標準C言語はパソコン以外の制御用マイコンチップなどの組み込みOSなどにも用いられる事があるため、C言語の規格では必要最低限の機能しか搭載していない。
 
LinuxやBSDなどのオープンソースOS用のコンパイラ言語処理系であるGCCやClang などで、あるコードの動作が確認できても、あくまでパソコン用のOSでだけ動作が確認されたにすぎず、はたしてそのコードがマイコン組み込みOS上のC言語でも動作するかは未知数である。
 
 
2010年以降、モダンなプログラム言語には、関数の中で関数を定義する機能が搭載されているモノも、実は多い。(ただし、比較的に新しい機能であるので、市販の入門書には紹介されていない。)
 
C言語コンパイラ言語処理系およびC++コンパイラ言語処理系は、他の多くの言語のコンパイラ言語処理系やインタプリタを作るための道具でもあるので、そういったモダンな別言語との互換性も考えて、実は規格にはない機能も、実装されたコンパイラ言語処理系には搭載されている場合もある。
 
だが、コンパイラ言語処理系の種類ごとに、規格にない機能が異なる場合もあるので、互換性などの観点からは、あまり規格外の機能は用いないほうが安全である。
 
== 脚注・出典など ==