「C言語/関数」の版間の差分
削除された内容 追加された内容
初出の「関数」に「かんすう」と読みを追加。 |
ネストのローカル変数とグローバル変数 |
||
728 行
</syntaxhighlight>
== ネストのローカル変数とグローバル変数 ==
なんらかの処理の中で、if文やfor文も使わずに <code>{ }</code> だけで処理をまとめた場合、その動作は難しい。
一例として、gccおよびclangを標準C言語としてコンパイルした場合、下記のコードは下記のような動作になる。
本節では便宜上、<code>{ }</code> カッコだけで処理をまとめたものを「ネスト」と呼ぼう。「ネスト」とは「入れ子」の意味である。
;ネスト中で再宣言の場合
ネスト中で変数を再宣言した場合、その変数はローカル変数的に振る舞うのが、パソコン環境では一般的である。
:コード
<syntaxhighlight lang="C">
#include "stdio.h"
#include "string.h"
int main(){
int a=3;
printf("ネストの前 %d \n",a);
{
int a = 10; // int で再度、宣言
printf("ネストの内部 %d \n",a);
}
printf("ネストを抜けた %d \n",a);
}
</syntaxhighlight>
結果
<pre>
ネストの前 3
ネストの内部 10
ネストを抜けた 3
</pre>
:(※ 動作確認: GCCおよびClangで、Fedora32上で2020年6月25日に動作を確認)
;ネスト中で再宣言しない場合
ネスト中で変数を再宣言しない場合、その変数はグローバル変数的に振る舞うのが、パソコン環境では一般的である。
:コード
<syntaxhighlight lang="C">
#include "stdio.h"
#include "string.h"
int main(){
int a=3;
printf("ネストの前 %d \n",a);
{
a = 10; // int が無くても実行可能
printf("ネストの内部 %d \n",a);
}
printf("ネストを抜けた %d \n",a);
}
</syntaxhighlight>
結果
<pre>
ネストの前 3
ネストの内部 10
ネストを抜けた 10
</pre>
:(※ 動作確認: GCCおよびClangで、Fedora32上で2020年6月25日に動作を確認)
ネストを抜けた3行目が「10」に置き換わっている事に注目しよう。
;解説や背景事情など
C++ では、構造体やクラスで定義できる「メンバ関数」を用いて、関数の内部に関数を定義する事が可能である。
それらC++クラスのメンバ関数を使うと、関数のなかで別の関数(メンバ関数である)を、(C++では)定義することができ、しかも動作が(C++のメンバ関数では)保証されている。
一方、標準C言語には、そのようなメンバ関数が無い。標準C言語の構造体のメンバに、関数を登録することは不可能である。
また、パソコンが発展してどんなに高性能になっても、標準C言語はパソコン以外の制御用マイコンチップなどの組み込みOSなどにも用いられる事があるため、C言語の規格では必要最低限の機能しか搭載していない。
LinuxやBSDなどのオープンソースOS用のコンパイラであるGCCやClang などで、あるコードの動作が確認できても、あくまでパソコン用のOSでだけ動作が確認されたにすぎず、はたしてそのコードがマイコン組み込みOS上のC言語でも動作するかは未知数である。
2010年以降、モダンなプログラム言語には、関数の中で関数を定義する機能が搭載されているモノも、実は多い。(ただし、比較的に新しい機能であるので、市販の入門書には紹介されていない。)
C言語コンパイラおよびC++コンパイラは、他の多くの言語のコンパイラやインタプリタを作るための道具でもあるので、そういったモダンな別言語との互換性も考えて、実は規格にはない機能も、実装されたコンパイラには搭載されている場合もある。
だが、コンパイラの種類ごとに、規格にない機能が異なる場合もあるので、互換性などの観点からは、あまり規格外の機能は用いないほうが安全である。
== 脚注・出典など ==
<references/>
|