FORTRANプログラマーのためのC | (1) |
AS/400のFORTRANのサポートがなくなりました。(PL/1もです)
FORTRAN発表当初から、販売を推進しないという変な方針だったらしいのですが、
ここへきて、PL/1,FORTRANとサポートしないというのはどういうことなのでしょう。
ともあれ、FORTRAN利用者にとってはゆゆしき問題です。
ここでは、FORTRANとC(ILE−C)を対比させて、FORTRAN→Cの変換の一助と
したいと思います。
ここでは、ILE−Cを単にCと呼びます。
◆サンプル
まずFORTRANとCのサンプルを紹介します。
FORTRAN WRITE(6,10) 10 FORMAT (' FORTRAN-PROGRAM') STOP END
Cvoid main() { printf("C-PROGRAM\n"); }
FORTRANのプログラムでは' FORTRAN-PROGRAM'という文字列を出力しています。
WRITE(6,10)の6は標準の出力装置の番号で、一般に印刷装置です。
FORMATは出力様式を記述する文で、ここでは
' FORTRAN-PROGRAM'
の文字列を出力装置に出力するよう記述しています。
FORTRANでは主プログラム、サブプログラム、関数プログラムの種類がありますが、
Cではプログラムを全て関数として記述します。例では main という関数として記述しています。
voidは関数からの戻り値がないということで、mainのうしろの () は関数 main に渡す引数がないことを示しています。
{ }内には、処理手順を記述します。
例の処理手順では printf という関数を呼出しています。printf はあたえられたデータを文字列に変換して出力する関数です。
サンプルでは
"C-PROGRAM\n"
の文字列を(そのまま)出力しています。文字列の最後の '\n' は、16進数の’0A’で文字を出力後
改行させる制御文字です。FORTRANのサンプルではこれに相当するものはありませんが、
WRITE命令の先頭の1バイトが、このような制御文字として使用される規則になっています。
FORTRANのサンプルでは、実際は制御文字としてのブランクに加えて
'FORTRAN-PROGRAM'を出力していることになります。
◆Cの特徴
サンプルで出てきたように、Cではプログラムを基本的に関数を構成するものとしています。
メイン・プログラムすらOSから制御が渡たされる’main’という特別な関数であり、
そのmainもいくつかの関数で構成されるということです。
さらにFORTRANにない特徴としては、記憶域の取得と開放ができるということです。
これによって自分が自分を呼び出すような、再帰的なプログラムを組むことができます。
◆コーディング様式
FORTRANはステートメント番号のフィールド、継続のフィールド、命令文のフィールド、
プログラムの識別用のフィールドが固定されています。
1 5 6 7 72 73 80A B C D
FORTRANのフィールド
A ステートメント番号。第一カラムにCまたは*を入れるとその行は注釈文となる。
B 継続用フィールド。ブランク以外の文字をいれると前の行の継続行となる。
C 命令文用テキストフィールド
D 識別用フィールド。自由使用。注釈他
Cの書式ではカラムによる固定はありません。1行で複数の命令を記述することもできるし、命令を何行にわたっても
記述することができます。コーディングの約束は次のとおりです。
1.自由形式の記述
2.コメントは/* */の中に入れる。
3.識別名は英字の大文字、小文字と_(下線)で始まる31桁までの文字列。先頭でなければ数字も使用できる。
4.命令の終わりは;(セミコロン)で終わる
5.予約語として以下のものがある。
予約語
意味・働き
auto
自動変数の宣言
char
文字型変数の宣言
double
倍精度浮動小数点変数の宣言
extern
外部変数の宣言
float
浮動小数点変数の宣言
int
整数型の宣言
long
倍精度整数型の宣言
register
レジスター変数の宣言
short
短い整数型の宣言
static
静的変数の宣言
struct
構造体の宣言
typdef
型の定義
union
共用体の宣言
unsigned
符号無し整数の宣言
break
ループからの飛び出し
case
多条件分岐を構成する分岐の一つの指定
continue
次の繰返しへ戻る
default
他条件分岐の省略時分岐の指定
do
doループ
else
if〜else
for
forループ
goto
無条件分岐
if
条件判定
return
呼出し側への戻り
switch
多条件分岐
while
whileループ
entry
意味なし
sizeof
データ型の長さ
◆データの種類
Cで使用できるデータの種類とFORTRANでの対応は次のとおりです。
FORTRAN 定数の例 C INTEGER*2 1 short int INTEGER 1234567 int または long REAL 3.4 float REAL*8または
DOUBLE PRECISION4.5D+6 double CHARACTER*n ’ABC’ char[n] COMPLEX 1+2.3I 該当なし COMPLEX8 該当なし LOGICAL .TRUE./.FALSE. 該当なし
このほかに、Cではポインターと呼ぶアドレスデータを扱うことができます。
また、ポインターで示された個所のデータを扱うこともできます。
注意:
1.int はパソコン系では2バイトの整数のこともあります。移植の場合は要注意です。
2.FORTANの倍精度の定数は1.23D±nのようにした場合に倍精度になります。
それ以外は短精度になるので注意が必要です。
3.Cでは、
1.0D+12 は不可(FORTRANでは可)
1.0E+12 はOK
となります。
3.Cにおける文字列定数は”ABC”の場合、実際は’ABC¥0’のデータで扱われます。
¥0はヌル文字で、16進の00で”ABC”は16進表示では、X’C1C2C300’と
なります。
◆変数名
変数名の規約は次のとおりです。
FORTRAN C 英字大文字と数字_(下線) 英字大文字と数字 英字大文字、小文字と数字と_(下線) 英字で始まる 英字大文字小文字と_(下線)で始まる 8桁まで 31桁まで
ここでは、Cの変数名ではできるだけ小文字を使用しないで話をすすめます。
◆省略時解釈
FORTRANでは、I からNまでの英字で始まる変数は、省略時解釈で整数(4バイトを使用する)、
それ以外は短精度の浮動小数点数(4バイトを使用する)です。Cでは省略時解釈はありません。
◆省略時解釈の変更宣言
FORTRANでは省略時解釈を変更するIMPLICIT命令がありますが、Cではありません。
例:
IMPLICIT INTEGER(X)
この例では、特に明示的宣言をしない限り、Xで始まる全ての変数がINTEGERになります。
明示的宣言とは、次のように、その属性をはっきり宣言するものをいいます。
例:
INTEGER*2 A,B,C
REAL*8 D,E,F
◆配列
Cでは配列定義のDIMENSION文に相当するものはありません。
それぞれのデータ定義に配列要素の数を記述すると配列となります。
例
DIMENSION ARAY(3,4,5)・・・・FORTRAN
float ARAY[3][4][5]; ....C
◆配列の添字
FORTRANでは配列の1番目の添え字は1ですが、Cでは1番目は0なので要注意です。
これはCの配列が、
配列名: 配列の始まりの位置のアドレス。
添え字: そのオフセット
としているためのようです。
例:
DIMENSION TBL(10) 添え字は1〜10まで。
float TBL[10]; /* 添え字は0〜9まで。 */
このため、FORTRANから変換するような場合は、できるだけFORTRANソースに変更を加えないよう
配列の要素数を1だけ増やし、0番目を使用しないようにする方法が考えられます。
また、メモリー上の配置と添え字の関係は、FORTRANでは左端の添え字がはやく回るように配置されますが、
Cでは右端の添え字が早く回るように配置されるので、注意が必要です。
FORTRAN
DIMENSION A(3,4)
メモリー上の配置は、以下のように配置されます。
A(1,1) A(2,1) A(3,1) A(1,2) A(2,2) A(3,2) A(1,3) A(2,3) A(3,3) A(1,4) A(2,4) A(3,4)
C
float A[3][4];
メモリー上の配置は、以下のように配置されます。
A[0][0] A[0][1] A[0][2] A[0][3] A[1][0] A[1][1] A[1][2] A[1][3] A[2][0] A[2][1] A[2][2] A[2][3]
◆初期値の設定
FORTRANでは初期値の設定はDATA命令文で行います。Cでは属性定義文で設定します。
例:
DATA A/123.0/B/456.78/
REAL C(3)
DATA C/3.0,4.0.,5.0/
float A=123.0;
float B=456.78;
float C[3]={3.0,4.0.,5.0}
◆同一アドレスの参照。
EQUIVALENCE
EQUIVALENCEは、FORTRANで複数の変数に同一アドレスを共有させるための定義です。
FORTRANでは実数と整数の変数を共有させて、型変換なしに(ビットパターンの変更なしに)
データを割りつけしたいときなどに使用されます。
Cでは union がこれに相当します。
例:
EQUIVALENCE (ABC,XYZ)
EQUIVALENCE (I,X)
union UT {
int I ;
float X ;
} UN ;
UTは共用体タグと呼ばれるもので、定義そのものの名前と考えてください。UNは共用体名です。
unionで定義した変数を使用する場合は、UN.Xのように共用体名で修飾して使用します。
FORTRANからの変換のような場合は、変更量が多くなるので、プリ・プロセッサー命令の
#defineを使用すると便利です。
#define ABC U.abc
このようにすると、コンパイラーはコンパイルに先立ち、ABCという変数は全て、U.abcに
変換してくれるので、FORTRANから変換するような場合、ソースの訂正量が少なくなります。
共用体を使用しないで同様のことを実現するにはポインターを使って次のように実現します。
float XYZ;
float *ABC;
ABC=&XYZ; /* XYZのアドレスをABCに入れる */
*ABCはポインターABCによって指し示す場所のデータの参照です。
単にABCとするとそのアドレスそのものを示します。
この場合もFORTRANでは、
PQR=ABC
のコーディングであったものが、
PQR=*ABC
のように変更しなければなりません。この変更量が多いときは、先のunionの場合と同様に、
変数*ABCを*abcのように変更しておいて、
#define ABC *abc
とマクロ名ABCと定義すれば、FORTRANのソースはもとのままで使用できます。
配列に配列の一部を重ねるEQUIVALENCE
DIMENSION A(5),TABEL(10)
EQUIVALENCE (A(1),TABLE(6))
このFORTRAN例では配列Aは、TABLEの6番目から10番目に重なるように位置します。
Cでは同じくポインターを使って、
float TABEL[10];
float *A;
として、AにTABLEの6番目のアドレスを次のようにセットします。
A=&TABEL[5];
こうすると、配列AはTABEL[5]のアドレスから、(すなわちTABELの6番目から10番目まで)重なることになります。
注意:Cの配列の添え字が0始まりなので[5]が6番目になることに注意して下さい。
メモリー上の配置関係は次のようになります。
A[0] TABEL[5] A[1] TABLE[6] A[2] TABEL[7] A[3] TABEL[8] A[4] TABEL[9]
例:
配列を別の配列の一部にかさねる。
#include <stdio.h> #include <stdlib.h> void main() { long A[100] ; long *B ; int X ; for (X=0; X<100 ;X++) { A[X]=X;} B = &A[10] ; for (X=0; X<10 ;X++) { printf ("B[%d]=%d??/n",X,B[X]); } }
◆演算
算術演算子は次のように対応します。
FORTRAN C 加算 + + 減算 − − 乗算 * * 除算 / / 累乗 ** 対応なし
累乗は対応する演算はありません。累乗関数powを使用します。
例えばAの3.1乗はpow(A,3.1)のようにします。
◆比較演算、論理演算
比較演算,論理演算は次のように対応します。
FORTRAN C .LT. < .GT. > .LE. <= .GE. >= .EQ. == .NE. != .AND. && .OR. || .NOT. !
◆実行制御
GO TO ステートメント番号
goto ラベル名;
FORTRANのステートメント番号はラベルに相当します。
ラベルの命名規則は、変数名の場合と同じです。
例:
GO TO 200
goto L200;
注:ここではFORTRAN表記に近づけるため、ステートメント番号に「L」をつけてラベル名としています。
計算型GO TO
GO TO (10,20,30,40),N
Nの値によって実行位置を変えるGOTOは、Cでは対応する命令がありません。
switch命令とcase文で実現します。
switch (N) { case 1: goto L10; break; case 2: goto L20; break; case 3: goto L30; break; case 4: goto L40; break; }
◆条件分岐
計算型IF
IF (式)10,20,30
計算型IFは、式の計算結果がマイナスなら、10へ、0なら20へ、プラスなら30へ実行を移します。
Cでは3個の if 命令に分解して対応させます。
if (式<0)goto L10;
if (式=0)goto L20;
if (式>0)goto L30;
条件式によるIF
IF (論理演算式) 1個の命令
論理演算式が.TRUE.のとき、指定した命令が実行されます。Cでは次のような形になります。
if (論理演算式) 1個の命令;
論理演算式とは、演算結果が「真」か「偽」どちらかの値になるような式をいいます。
FORTRANの例: A.LT.B.AND.C.GE.D
Cの例: A<B && C>=D
ELSEの伴うIF
IF (論理演算式)
複数の命令
ELSE
複数の命令
END IF
Cではブロック記号{ }を使用して次のようになります。
if (論理演算式){
複数の命令
}
else{
複数の命令
}
{ }は「有効範囲」を定義する記号です。(厳密には複数の文をひとつの文にまとめるという方が正しい)
◆繰返し処理
FORTRANでの典型的な繰返し処理は、DO文を使用した繰返し処理です。
例:
DO 99 I=1,10,2
複数の命令
99 CONTINUE
Cではfor文が該当します。
for (I=1;I<=10;I=I+2){
複数の命令
}
Cの解説本やマニュアルにあるI++はI=I+1の機能がありますが、使用しても取り立てて生産性が
よくなるわけでもないし、その「お約束」を知らないとデバッグすらできなくなるので、FORTRANプログラマーには
おすすめしません。
◆CALL命令はない
CALL命令相当の命令はCでは関数呼出で行います。CALLという命令はありません。
例:
CALL SUB1(A,B,C)
sub1(A,B,C);
FORTRANでは、呼び出すサブルーチンにパラメータを渡すときは、コンパイラーはアドレス・リストという
データの所在を示すアドレスの一覧表を作ってそのあり場所を渡します。
Cでは原則として、「データ渡し」でデータの複製を作成し、そのあり場所を渡します。
したがって、呼び出された関数の中でパラメータの値を変更しても、それを呼出元へ返すことができません。
呼び出された関数内で変更された値を返すには、次のどれかの方法で行います。
(1)関数の戻り値を使う。
(2)自分で呼出元のデータのアドレスを渡し、その場所のデータを関数にも使用(変更)させる。
(3)パラメータとして配列データを使用する。
(1)の例
float SUB1(float A, float B) { float C ; C=A+B ; return C; } 呼出側 Z=SUB1(X,Y);
(2)の例
void SUB1(float A, float B, float *C) { *C = A + B ; } 呼出側 SUB1(X,Y,&Z) ;
&Zは「Zのアドレス」という意味です。*Cは「Cのアドレスにあるデータ」という
意味です。*こみでひとつの変数の感覚で使用します。
「桃奴姉さん」という代わりに、「門前仲町の・・・」で済ますというような感じです。
(3)の例
void SUB1(float AR[]) { AR[2]=AR[0]+AR[1] ; } 呼出側 AR[0]=A ; AR[1]=B ; SUB1(AR) ; C=AR[2] ;
配列でパラメータを授受する場合は、配列の先頭のアドレスを呼出関数に渡します。
すなわち、一種のアドレス渡しとなっているわけです。
FORTRANプログラマーの感覚からすれば、一番なじみやすい方法かもしれません。
◆標準装備の関数
メーカーで予め準備した関数があります。これらはヘッダーファイルというファイルに入っており、
プリプロセッサー命令の#include命令で取り込みします。
たとえば、数学関数cosを使用する場合は、
#include <math.h>
のようにコンパイル時に前処理でソースを取り込みさせます。
メーカーで予め準備した関数については別ページで紹介します。(工事中)
目 次 次ページ
(C)COPYRIGHT ISHIOKA KATSUHIDE ,2000