プロが教えるわが家の防犯対策術!

Windows Vista Home PremiumにFTN95をインストールしたPCにて、Fortranのプログラミングをし始め、「Cpad for Salford FTN77」を利用してプログラミングをしています(FORTRAN77・Fortran90ともに)。FTN95でのFortranプログラミングに際し、FortranプログラムからC言語で実装された関数を呼ぶには、どのように対処すれば可能になりますでしょうか?
ユーザーガイドによれば、「Fortranプログラム中に、C_EXTERNALという宣言をした関数は、Cの関数と同じくアクセスできるようになり、C側では、#extern <返り値>関数名(引数)を与えれば、Cの関数として呼び込むことができる。」とのことがかかれています。
実際に使っているファイルをいくつか書き出します。

<D:\fortran\sample.f>
C_EXTERNAL WRITE 'WriteFile' : INTEGER*4
INTEGER*4 RESULT
RESULT=WRITE()
write(*,*) result
return
end
<D:\fortran\sample.c>
#extern int Writefile(int);
<C:\Program Files\Silverfrost\FTN95\ftn95c.bat>
ftn95.exe %1 %2 %3 %4 %5 %6 %7 %8 %9 /link

ちなみに、「Cpad for Salford FTN77」での実行/設定/実行/コンパイル時のパラメータは「/link /dreal」です。もちろんftn95.exeへのパスは通してあります。何が問題でしょうか?
何分初心者ですので、拙い質問かと思いますが、何卒ご教示願います。

A 回答 (9件)

ftn77 と ftn95 で違ったりするみたいですね。


コンパイルオプションでどうにかなるのかもしれませんが、とりあえずC側のファイルの関数名を

hello から HELLO のように全部を大文字にしてください。
これでリンクが通るようになると思います。

この回答への補足

貴殿のアドバイスのお陰で無事当方で実行したいことが可能になりました。試行錯誤の結果、ftn95のパラメータには今回のケースでは「/dreal」だけでなく「/ckc」もいるということがわかり、下記の通り、sccでもgccでも共に無事成功しました。何度も何度も拙い質問に堪えながらの回答ありがとうございました。またわからないことが生じましたら、そのときは再度アドバイスよろしくお願いいたします。
D:\math\fortran>ftn95 /dreal /ckc tes1.f
[FTN95/Win32 Ver. 5.01.0 Copyright (c) Silverfrost Ltd 1993-2006]
NO ERRORS [<main program> FTN95/Win32 v5.01.0]

D:\math\fortran>scc lib.c
[Silverfrost SCC/WIN32 Ver 3.65 Copyright (c) Silverfrost Ltd 2006]
NO ERRORS [<LIB> SCC/WIN32 Ver 3.65]

D:\math\fortran>type tes1.f
implicit double precision(a-h, o-z)

C_EXTERNAL near
C_EXTERNAL down
C_EXTERNAL up
C_EXTERNAL chop
C_EXTERNAL hello

dimension a(100),b(100)

cn=0.0d0
cu=0.0d0
cd=0.0d0
cc=0.0d0

do i=1,100
a(i)=0.1d0
b(i)=0.1d0
end do

call near
do i=1,100
cn=cn+a(i)*b(i)
end do

call up
do i=1,100
cu=cu+a(i)*b(i)
end do

call down
do i=1,100
cd=cd+a(i)*b(i)
end do

call chop
do i=1,100
cc=cc+a(i)*b(i)
end do

write(6,10) cn,cu
write(*,*)
write(6,10) cd,cc
10 format(f26.19,2x,f26.19)

call near
end
D:\math\fortran>type lib.c
#include <stdio.h>

int _RoundNear =0x133a;
int _RoundDown =0x173a;
int _RoundUp =0x1b3a;
int _RoundChop =0x1f3a;

extern "C" void NEAR(void)
{
asm{fldcw _RoundNear};
printf("%s\n", "Near");
}

extern "C" void DOWN(void)
{
asm{fldcw _RoundDown};
printf("%s\n", "Down");
}

extern "C" void UP(void)
{
asm{fldcw _RoundUp};
printf("%s\n", "Up");
}

extern "C" void CHOP(void)
{
asm{fldcw _RoundChop};
printf("%s\n", "Chop");
}

D:\math\fortran>slink tes1.obj lib.obj
Creating executable: D:\math\fortran\tes1.exe

D:\math\fortran>tes1
Near
Up
Down
Chop
1.0000000000000006661 1.0000000000000008882

0.9999999999999934497 0.9999999999999934497
Near

D:\math\fortran>type lib2.c
#include <stdio.h>
int _RoundNear =0x133a;
int _RoundDown =0x173a;
int _RoundUp =0x1b3a;
int _RoundChop =0x1f3a;
void NEAR()
{
asm volatile("fldcw __RoundNear");
printf("%s\n", "Near");
}

void DOWN()
{
asm volatile("fldcw __RoundDown");
printf("%s\n", "Down");
}

void UP()
{
asm volatile("fldcw __RoundUp");
printf("%s\n", "Up");
}

void CHOP()
{
asm volatile("fldcw __RoundChop");
printf("%s\n", "Chop");
}

void HELLO()
{
printf("%s\n", "hello from C function!");
}

D:\math\fortran>gcc -c lib2.c

D:\math\fortran>slink tes1.obj lib2.o
Creating executable: D:\math\fortran\tes1.exe

D:\math\fortran>tes1
Near
Up
Down
Chop
1.0000000000000006661 1.0000000000000008882

0.9999999999999934497 0.9999999999999934497
Near

D:\math\fortran>

補足日時:2009/05/14 15:24
    • good
    • 0
この回答へのお礼

貴殿のアドバイスのお陰で無事当方で実行したいことが可能になりました。試行錯誤の結果、ftn95のパラメータには今回のケースでは「/dreal」だけでなく「/ckc」もいるということがわかり、sccでもgccでも共に無事成功しました。何度も何度も拙い質問に堪えながらの回答ありがとうございました。またわからないことが生じましたら、そのときは再度アドバイスよろしくお願いいたします。

お礼日時:2009/05/14 15:32

C_EXTERNAL hello



C_EXTERNAL hello 'hello'
にしたら動いたりして.
    • good
    • 0

>パスを通した上でコマンドプロンプトから「gcc lib.c」とするとエラーとなり、



ここで、gcc -c lib.c

のようにしてください。
これをつけないとlib.cだけで実行ファイルを作りに行ってしまうので
それが理由でエラーになります。

あれ、でも#3の補足を見るとオブジェクトファイルが、とかあるなあ。
まあそれはおいといて、

-cをつけると、(エラーがなければ)lib.o を作って終わりますから
Fortranのソースからできた sample.obj と一緒にリンクしてください。
あ、Fortranのコンパイルも
ftn95.exe /link /dreal sample.f /link
の /link は指定しないでくださいね。

ftn95 dreal sample.f
gcc -c lib.c
slink sample.obj lib.o
てな手順で sample.exe が最終的に手に入るはずです。

この回答への補足

「gcc -c」で対処しても下記の通りうまくいきませんでしたので、「scc」でやってみましたが結局現状ではどちらも当方ではうまく動きません。

D:\math\fortran>type tes1.f lib.c

tes1.f


program mogera
C_EXTERNAL hello
call hello
stop
end

lib.c


#include <stdio.h>
#define near() asm volatile("fldcw __RoundNear")
#define down() asm volatile("fldcw __RoundDown")
#define up() asm volatile("fldcw __RoundUp")
#define chop() asm volatile("fldcw __RoundChop")
int _RoundNear =0x133a;
int _RoundDown =0x173a;
int _RoundUp =0x1b3a;
int _RoundChop =0x1f3a;
void hello()
{
printf("%s\n", "hello from C function!");
}

D:\math\fortran>ftn95 /dreal tes1.f
[FTN95/Win32 Ver. 5.01.0 Copyright (c) Silverfrost Ltd 1993-2006]
NO ERRORS [<MOGERA> FTN95/Win32 v5.01.0]

D:\math\fortran>gcc -c lib.c

D:\math\fortran>slink tes1.obj lib.o
WARNING the following symbols are missing:
HELLO D:\math\fortran\tes1.obj
(D:\MATH\FORTRAN\TES1.F)
Creating executable: D:\math\fortran\tes1.exe

D:\math\fortran>tes1

D:\math\fortran>type error.txt
Runtime error from program:d:\math\fortran\tes1.exe
Run-time Error
*** Error 29, Call to missing routine : _HELLO at 0x00401020.


00401000 main [+0025] [recur= 1]


D:\math\fortran>

補足日時:2009/05/13 23:27
    • good
    • 0
この回答へのお礼

重要な点を含んだ回答していただき、ありがとうございます。何度も何度も回答していただいているにも関わらず、当方での動作がうまくいかず「再質問→再回答」の繰り返しとなっていること、申し訳なく思います。
さて、プログラムのほうは貴殿のようにうまく動きません。少なくとも「tes1.f」・「lib.c」についてはそれぞれ「ftn95」・「scc」で単体でなら何のエラーも返さずにコンパイルできます。しかし、「slink」の段階でWarningが出てきてしまい、実行ファイルができるにはできてもエラーになってしまいます。どのようにすれば対処できますでしょうか?

D:\math\fortran>type tes1.f lib.c

tes1.f


program mogera
C_EXTERNAL hello
call hello
stop
end

lib.c


#include <stdio.h>
#define near() asm volatile("fldcw __RoundNear")
#define down() asm volatile("fldcw __RoundDown")
#define up() asm volatile("fldcw __RoundUp")
#define chop() asm volatile("fldcw __RoundChop")
int _RoundNear =0x133a;
int _RoundDown =0x173a;
int _RoundUp =0x1b3a;
int _RoundChop =0x1f3a;
void hello()
{
printf("%s\n", "hello from C function!");
}

D:\math\fortran>ftn95 /dreal tes1.f
[FTN95/Win32 Ver. 5.01.0 Copyright (c) Silverfrost Ltd 1993-2006]
NO ERRORS [<MOGERA> FTN95/Win32 v5.01.0]

D:\math\fortran>scc lib.c
[Silverfrost SCC/WIN32 Ver 3.65 Copyright (c) Silverfrost Ltd 2006]
NO ERRORS [<LIB> SCC/WIN32 Ver 3.65]

D:\math\fortran>slink tes1.obj lib.obj
WARNING the following symbols are missing:
HELLO D:\math\fortran\tes1.obj
(D:\MATH\FORTRAN\TES1.
Creating executable: D:\math\fortran\tes1.exe

D:\math\fortran>tes1

D:\math\fortran>type error.txt
Runtime error from program:d:\math\fortran\tes1.exe
Run-time Error
*** Error 29, Call to missing routine : _HELLO at 0x00401020.


00401000 main [+0025] [recur= 1]


D:\math\fortran>

お礼日時:2009/05/13 23:27

.... 誰だ, 「gcc での~ないといけないのです」なんて中途半端なことを言ったやつは....


「コンパイルするだけ」なら main はいらない. gcc だろうと cl だろうと同じこと. たぶん scc でも同じはずだ.
もちろん「リンクして実行ファイルを作る」ためには main が必要.
「コンパイルする」ことと「リンクして実行ファイルを作ること」とは別です. 区別してください.
    • good
    • 0
この回答へのお礼

>.... 誰だ, 「gcc での~ないといけないのです」なんて中途半端なことを言ったやつは....
>「コンパイルするだけ」なら main はいらない. gcc だろうと cl だろうと同じこと. たぶん scc でも同じはずだ.

パスを通した上でコマンドプロンプトから「gcc lib.c」とするとエラーとなり、何のファイルもはき出されません。実際のエラーメッセージは次の通りです。

C:/MinGW/bin/../lib/gcc/mingw32/3.4.5/../../../libmingw32.a(main.o):main.c:(.text+0xbd): undefined reference to WinMain@16'
collect2: ld returned 1 exit status

「scc」でコンパイルする際に、「asm volatile("...")」 という形でアセンブリコードを埋め込むことができないのならば、sccはどのように記述すればいいのでしょうか?
「FTN95」に「scc」もすでにインストール済みなわけで、すでにあるものの有効活用でいけるところまでいってみたいと思うのです(「むしろ、そっちのほうが難しいんだよ!」と突っ込まれるかもしれませんが…)。

お礼日時:2009/05/13 18:33

まさかまさかなんだけど, C のソースに「関数 main がある」ってオチはないよね?

    • good
    • 0
この回答へのお礼

回答ありがとうございます。「gcc」でのコンパイルには最低限

int main(){
return 0;
}
がないといけないのです。「FTN95」付属の「scc」ではそうではありませんが…。

部分的には貴殿の“オチ”のとおりかもしれません…。

お礼日時:2009/05/13 14:19

scc というのがわたしがインストールしたものには入っていなかったので


すぐには確認できませんが、それがCコンパイラなら使えるのではないかと思います。
ただ、asm volatile("...") という形でアセンブリコードを埋め込むことは
できないと思われますので、scc 用の記述に変えるなりしなければならないのではないでしょうか。

もうひとつ、Visual C/C++ ですがExpress edition というものが
無料配布されていて、これを使うことができるでしょう。

Visual Studio 2008 Express Edition の DVD イメージからのインストール
http://www.microsoft.com/japan/msdn/vstudio/expr …
    • good
    • 0

>ご教示願います。


これ、相手に敬意をはらった書き方だと思って書いてます?

ま、それはともかくエラーメッセージにあるようにFORTRAN側の
プログラムからして間違ってますし、C側も補足で出されたのも含めて間違ってます。
C_EXTERNAL WRITE 'WriteFile' : INTEGER*4
INTEGER*4 RESULT
RESULT=WRITE()
write(*,*) result
return
end

サブルーチンでもないのに、returnがあるのは間違いということで
コンパイルできてません。

手元にあって試したのはFTN77ですが、基本的には同様にできるはずです。

C:\win32app\salford>type moge.f
program mogera
C_EXTERNAL hello
call hello
stop
end

というFORTRANプログラムで、helloがCで記述したサブルーチンです。
C:\win32app\salford>ftn77 moge.f
[Salford FTN77/Win32 v4.03, Copyright (c) Salford Software Ltd. 1988-1998]
Licensed to: FTN77 Personal Edition
Department: Non-commercial use only
NO ERRORS [<MOGERA>FTN77 Ver 4.03]

で、C側はこう。
C:\win32app\salford>type lib.c
#include <stdio.h>

int _RoundNear =0x133a;
int _RoundDown =0x173a;
int _RoundUp =0x1b3a;
int _RoundChop =0x1f3a;
void
near()
{
__asm fldcw _RoundNear
}
void
down()
{
__asm fldcw _RoundDown
}
void
up()
{
__asm fldcw _RoundUp
}
void
chop()
{
__asm fldcw _RoundChop
}

void
hello()
{
printf("%s\n", "hello from C function!");
}

C:\win32app\salford>cl -c lib.c
Microsoft(R) 32-bit C/C++ Optimizing Compiler Version 13.10.3077 for 80x86
Copyright (C) Microsoft Corporation 1984-2002. All rights reserved.

lib.c

C:\win32app\salford>slink.exe moge.obj lib.obj
Creating executable: C:\win32app\salford\moge.exe

C:\win32app\salford>moge
hello from C function!

と、C側の関数の出力がされてます。
FORTRAN側でサブルーチンではなく関数として使うのであれば
多少変わりますが大まかな手順としてはこんな感じになります。

補足にあるCプログラムを見るとgcc用のようですが、FTN77やFTN95って
gccでコンパイルしてできた.oファイルもリンクしてくれるんでしょうか?
    • good
    • 0
この回答へのお礼

>>ご教示願います。
>これ、相手に敬意をはらった書き方だと思って書いてます?
当方の言葉の誤用で貴殿に対して失礼となる書き込みをしてしまったこと、心よりお詫び申し上げます。

本題ですが、FortranからCを呼び出すこと自体は問題なくできました。ありがとうございます。ただ、肝心のgccでコンパイルしたオブジェクトファイルでは、(拡張子をgccでのコンパイル時に「.obj」に指定したとしても)実行ファイルができてもエラーとなってしまいます。「『main』関数が2重に定義されている」とかいうメッセージがslink実行時に出てしまい、できた実行ファイルを実行してもエラーで止まってしまいます。

ちなみにFTN95に同梱されているsccではslink不能なのでしょうか。当方はVisual Studioは有しておりませんので「cl.exe」は当然入っておりません。簡単(?)なCの関数を呼び出すのに、さらに別のソフト(有料?)を入れるという大がかりなことをしないとだめなものなのでしょうか…。

何かいい解決法はないものでしょうか?お教え願います。

お礼日時:2009/05/13 00:18

エラーメッセージが出ているならそれを書いてください. もちろん「翻訳」なんかしないで, 一字一句そのままで.


ちょっと見た感じだと C の方は特にいじらなくてもいいように見えるけどなぁ....

この回答への補足

上述したエラーメッセージは以下の通りです(一字一句そのままです)。

■D:\math\fortran> ftn95c /link /dreal sample.f

D:\math\fortran>ftn95.exe /link /dreal sample.f /link
[FTN95/Win32 Ver. 5.01.0 Copyright (c) Silverfrost Ltd 1993-2006]
0005) return
*** RETURN cannot be inside a PROGRAM block
1 ERROR [<main program> FTN95/Win32 v5.01.0]
*** Compilation failed

なお、Cを呼び出す必要があるのは、Fortranの命令で浮動小数点をユーザーの希望するタイミングでUp・Down・Chop・Nearできないため、Cから呼び出すことでこれを実現したいからです。
ちなみに、<D:\fortran\sample0.c>も用意してあります。

<D:\fortran\sample0.c>
#include <stdio.h>
#define near() asm volatile("fldcw __RoundNear")
#define down() asm volatile("fldcw __RoundDown")
#define up() asm volatile("fldcw __RoundUp")
#define chop() asm volatile("fldcw __RoundChop")
int _RoundNear =0x133a;
int _RoundDown =0x173a;
int _RoundUp =0x1b3a;
int _RoundChop =0x1f3a;

int main()
{
return(0);
}

改めてご教示願います。

補足日時:2009/05/12 12:20
    • good
    • 0
この回答へのお礼

回答ありがとうございます。質問文の「D:\fortran\」は「D:\math\fortran\」の誤りです。訂正します。

お礼日時:2009/05/12 14:34

質問者さんの組み合わせはやったことがないのですが



<D:\fortran\sample.c>
#extern int Writefile(int);

C側がこれだけですか?
これだと、Cで関数の実装がされてませんけど。
それから、#extern というのはCコンパイラがエラーにしてしまうような気がするんですがユーザーガイドとやらを読み違えてたりしませんか?

FORTRAN側のプログラムもなんか変だなあ。

この回答への補足

上述したエラーメッセージは以下の通りです(一字一句そのままです)。

■D:\math\fortran> ftn95c /link /dreal sample.f

D:\math\fortran>ftn95.exe /link /dreal sample.f /link
[FTN95/Win32 Ver. 5.01.0 Copyright (c) Silverfrost Ltd 1993-2006]
0005) return
*** RETURN cannot be inside a PROGRAM block
1 ERROR [<main program> FTN95/Win32 v5.01.0]
*** Compilation failed

なお、Cを呼び出す必要があるのは、Fortranの命令で浮動小数点をユーザーの希望するタイミングでUp・Down・Chop・Nearできないため、Cから呼び出すことでこれを実現したいからです。
ちなみに、<D:\fortran\sample0.c>も用意してあります。

<D:\fortran\sample0.c>
#include <stdio.h>
#define near() asm volatile("fldcw __RoundNear")
#define down() asm volatile("fldcw __RoundDown")
#define up() asm volatile("fldcw __RoundUp")
#define chop() asm volatile("fldcw __RoundChop")
int _RoundNear =0x133a;
int _RoundDown =0x173a;
int _RoundUp =0x1b3a;
int _RoundChop =0x1f3a;

int main()
{
return(0);
}

改めてご教示願います。

補足日時:2009/05/12 14:27
    • good
    • 0
この回答へのお礼

回答ありがとうございます。質問文の「D:\fortran\」は「D:\math\fortran\」の誤りです。訂正します。

お礼日時:2009/05/12 14:33

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!