文には、式に;(セミコロン)をつけただけの単純なものから、定義を行うもの、プログラム制御文のように処理の流れを制御するものなどがあります。
ブロックとは、複数の文を{ }で囲い、1つのまとまりとして扱います。関数を定義するときや、本来1文しか書けない部分に複数の文を書くときに使用します。
変数、配列変数、関数は、使う前に定義文で定義しておく必要があります。
■変数定義文
書式)
型指定 変数名1, 変数名2, . . 変数名n;
解説)
型を指定し、その後に変数名を1つ以上記述します。
型には、short long int float doubleの何れかを書くことができます。
例)
int val1, val2, val3;
■配列定義文
書式)
型指定 配列面数名1[要素数1], 配列変数名2[要素数21][要素数22], ..配列変数名n[要素数n];
解説)
型を指定し、その後に、1次元配列の場合は、配列変数名と[ ]で囲んだ配列要素数を書きます。
2次元配列の場合は、配列変数と[]で囲んだ配列要素数1とさらに[ ]で囲んだ配列要素数2を書きます。
型には、short、long、int、float、doubleの何れかを書くことができます。
配列変数には、1次元配列と2次元配列があります。1つの配列変数定義文に、1次元配列と2次元配列を書くことができます。
例)
int array1[3], array2[5][3];
■const変数定義文
書式)
const 型指定 変数名 = 定数値;
解説)
constキーワードの後に、型を指定し、その後に変数名=定数値を書きます。
型には、short、long、int、float、doubleの何れかを書くことができます。
const変数は、プログラムの可読性、メンテナンス性を向上させるために使用します。
例)
const int ival = 2;
const double dval = 12.345;
const int aaa[] = {1,2,3,4,5};
■関数定義文
書式)
戻り値の型 関数名(引数1の型 引数1, 引数2の型 引数2, . . )
{
文
…
return( 式 );
}
解説)
戻り値の型は、void、short、long、int、float、doubleの何れかを書くことができます。
引数の型は、short、long、int、float、doubleの何れかを書くことができます。引数には、配列を書くことができます。
配列でない場合には、引数は値で関数に渡されますが、配列の場合には、参照が渡されます。したがって、配列を渡した場合、関数内で配列要素に代入した場合、関数呼び出し側の配列要素に代入したことになります。
例)
void main()
{
RobSetPtpSpeed(100);
RobPtpMove(pos1);
}
変数、配列変数に値を格納するための文です。
■変数への代入文
書式)
変数名 = 式;
解説)
short、long(int)、float、double型変数に値を代入します。
例)
val1 = val2 + 123.4;
■配列変数の要素への代入文
書式)
配列変数名[要素式] = 式;
配列変数名[要素式1][要素式2] = 式;
解説)
short、long(int)、float、double型の配列変数に値を代入します。
要素式の結果は、0から配列要素数-1である必要があります。
例)
val1[0] = val2 + 123.4;
val1[0][0] = a + b;
処理を実行させて結果を導き出したり、処理をまとめて簡略化したりするのに、関数を使用します。
関数には、システムにあらかじめ用意されているシステム関数と、プログラムで関数定義文によって定義されたユーザ関数があります。
関数呼び出し文は、システム関数、またはユーザ関数を実行し、返却値を得ます。
書式)
関数名(式1, 式2, . . );
変数 = 関数名(式1, 式2, . . );
解説)
関数名の後に、( )で囲って、実引数を表す式を , で区切って記述します。実引数の型と、個数は、各関数定義によって決まっています。実引数は、配列でない場合には、引数は値で関数に渡されますが、配列の場合には、参照が渡されます。したがって、配列を渡した場合、関数内で配列要素に代入した場合、関数呼び出し側の配列要素に代入したことになります。
また、2次元配列は2次元配列の1次元を指定して1次元配列として、引数とすることも可能です。
構造体の2次元配列、構造体の要素が2次元配列の場合も同様です。
関数が返却値を持つ場合、返却値を変数、または配列変数の要素に代入することができます。
例)
val1 = UserFunc(val2);
■関数引数に配列を使用する場合
ユーザ関数の引数に配列を使用する場合、配列要素数を指定する必要があります。
なお、引数に配列を指定した場合は参照渡しとなります。
例1)1次元配列の場合
int Sum1(int a[10])
{
int i;
int sum;
sum = 0;
for( i = 0; i < 10; i=i+1)
{
sum = sum + a[i];
}
return(sum);
}
void SetData1(int a[10])
{
int i;
for( i = 0; i < 10; i=i+1)
{
a[i] = 2;
}
}
例2)2次元配列の場合
int Sum2(int b[10][10])
{
int i;
int j;
int sum;
sum = 0;
for( i = 0; i < 10; i=i+1)
{
for( j = 0; j < 10; j=j+1)
{
sum = sum + b[i][j];
}
}
return(sum);
}
void SetData2(int b[10][10])
{
int i;
int j;
for( i = 0; i < 10; i=i+1)
{
for( j = 0; j < 10; j=j+1)
{
b[i][j] = 0;
}
}
}
上記例1)、例2)の実行方法
void main()
{
int data1[10];
int data2[10][10];
int s1;
int s2;
int i ;
int j ;
//初期化
SetData1(data1);
SetData2(data2);
//実行
s1 = Sum1(data1);
s2 = Sum2(data2);
Printf1("Sum1=%d\n", s1);
Printf1("Sum2=%d\n", s2);
}
ユーザ関数の関数定義文の先頭にlibfuncを指定すると、その関数はライブラリ関数となります。
ライブラリ関数に指定されたユーザ関数については、デバッグ時において次のような性質になります。
解説)
ライブラリ関数は、関数の途中で停止したくない、あるいは停止すると支障がある関数について、ステップ停止やブレーク停止をブロックすることができます。
デバッグの操作でステップ実行する場合、ライブラリ化されたユーザ関数に出会うとその関数はステップオーバされますので、デバッグの必要のない完成された関数として扱うことができ、効率的なデバッグを行うことができます。
例)
libfunc void ChuckCtrl(int sts) {
int counter;
WritePort(2113, sts); // ダブルソレノイド制御;
WritePort(2114, !sts);
counter = 0;
while(ReadPort(2049) != sts) {
Sleep(10);
counter = counter + 1;
if(counter > 50) {
// タイムアウト
return(1);
}
// 正常終了
return(0);
}
}
■if文
条件式の値によって実行する文を選択します。
書式)
if ( 条件式 ) { 文 };
※文が単文の場合であっても{}は省略できません。
解説)
1番目の書式では、条件式の値が真であれば、文を実行します。
2番目の書式では、条件式の値が真であれば文1を、偽であれば文2を実行します。
3番目の書式では、選択する条件が複数であるとき、if文を重ねて書くことができます。
例)
if(val1 == 0) {
val2 = 1;
}
if(val1 == 0) {
val2 = 1;
}
else {
val2 = 2;
}
if(val1 == 0) {
val2 = 1;
}
else if(val1 == 2) {
val2 = 1;
}
注意)
次のように記述した場合、通常のC言語ではf1()==1が偽の場合、f2()==2、f3()==3 の評価を行いませんが、MOSの場合、全部の評価を行います。f2()が、f1()が真であることを前提としている場合は問題となりますので、注意が必要です。
if( (f1() == 1) && (f2() == 2) && (f3() == 3) )
このような場合、次のような記述スタイルをご使用ください。
if(f1() == 1) {
if(f2() == 2) {
if(f3() == 3) {
■swith文
switch文は、多分岐をより簡潔に記述することができます。
書式)
switch ( 条件式 ) {
case 定数1:
文1;
break;
case 定数2:
文2;
break;
default:
文3;
break;
};
解説)
caseの後ろには定数とconst宣言された整数型変数のみが使えます。caseに書いた定数等がswitch文に書いた式の値と一致したとき、その次の文からbreakまでが実行されます。
例)
switch(val1) {
case ConstVal1:
case 12:
val2 = 0;
break;
case ConstVal2:
val2 = 1;
break;
default:
val2 = 2;
break;
};
■while文
条件式が成立している間、文を実行し続けます。
書式)
while ( 条件式 ) { 文 }
※文が単文の場合であっても{}は省略できません。
解説)
whileループは条件式が成立している間、文を実行し続けます。
例)
i = 0;
while(i < 100) {
UserFunc();
i++;
}
■return文
ユーザ関数の実行を終了し、関数の値として、式に値を返却します。
書式)
return( 式 );
解説)
式の値は、ユーザ関数定義文で定義された返却値の型に変換されて返されます。
例)
int FuncAdd(int a, int b)
{
return(a + b);
}
■goto文
指定したラベルの文に直接制御を渡します。
書式)
goto ラベル;
解説)
goto文は、指定したラベルの文に直接制御を渡します。
goto文が有効な範囲は、1つのユーザ関数の中です。
例)
if(error != 0) {
goto _ExitDoor;
}
…
_ExitDoor:
reurn(error);
■continue文
continue文は、これを囲むいちばん内側のwhileループ、forループの繰り返し位置に制御を渡します。
書式)
continue;
解説)
continue文はwhileループやforループの中で、ループ処理をその回だけスキップさせるために用いられます。(continue記述位置からループ終端部までの記述部分をスキップします。)
通常、if文と併用され、ループ処理の中で、ある条件が成立する場合、それ以下の処理を行わずにスキップします。スキップした後はまた元のループ処理に戻ります。ループがネスト構造になっている時は、continue文の存在するループの中でスキップ処理を行います。
例)
while(i < 1000) {
if (a[i] < 0) {
i = i + 1;
continue;
}
sum = sum + a[i]; // a[i]の値が負であればこの行はスキップされます(処理されない)
i = i + 1; // a[i]の値が負であればこの行はスキップされます(処理されない)
}
■break文
break文は、このキーワードを囲むいちばん内側のswitch文、whileループ、forループのいずれかを終了させます。
書式)
break;
解説)
break文はswitch文、またはwhile文によるループ、またはfor文によるループから脱出する制御文で、goto文なしでスマートにループを脱出することができます。
while文やfor文で用いるbreak文は、if文と併用します。ループがネスト構造になっている時は、break文の存在するループを1つだけ抜けます。
例)
while(a < 1000) {
if(a[i] < 0) {
break; // a[i]の値が負であればwhileループを抜けてPrintf1へ制御を移す;
}
sum = sum + a[i];
i++;
}
Printf1("sum = %d\n", sum);
■for文
条件式が成立している間、繰返し文を実行し続けます。
書式)
for( 初期化式; 継続条件式; 再初期化式 ) { 文 }
※文が単文の場合であっても{}は省略できません。
解説)
for文では、まずループ処理に入る前に初期化式を実行します。その後、継続条件式が真の間、文を実行します。各ループ処理のたびに、文の実行後、再初期化式を実行します。
これを繰り返し、最終的に継続条件式が偽になったときにループを抜けます。
例)
for(i = 0; i < 100; i++) {
UserFunc();
}