[英]Getting weird crashes in mixed fortran/C program
我正在嘗試在一組fortran程序中替換一些圖形代碼(而不是我自己的代碼)。 我得到了一個更簡單的代碼('psvdraw')可以正常工作,用C調用開羅庫(graphic_output.c)替換了fortran后記生成代碼。 我已經能夠成功解決跨語言調用,而沒有太多麻煩。
但是,當試圖使第二個更大的程序(“ pssect”)運行,調用相同的C代碼時,出現分段錯誤,或者在某些情況下,程序流返回到fortran例程“錯誤”(我確實不要在我的C代碼中調用此代碼或任何fortran例程)。
在嘗試診斷此問題時,我將一堆來自pssect的fortran代碼鏈接到psvdraw('biglib.f')中,並得到了相同的錯誤。 請注意,實際上沒有調用此添加的代碼! 錯誤也發生在從fortan到c代碼的第一次調用中。 因此:鏈接有biglib.f的psvdraw失敗,但沒有它的psvdraw成功。
這是makefile的相關位:
COMP77 = gfortran
FFLAGS = -C -v -pedantic -Wunused -fno-underscoring
CC = gcc-4
CFLAGS = -v -pedantic -Wunused
CAIRO_INCLUDE = /sw/include/cairo
CAIRO_LIB = /sw/lib
# PSVDRAW Make setup that works:
psvdraw: psvdraw.o graphic_output.o tlib.o pscom.o
$(COMP77) $(FFLAGS) $@.o graphic_output.o tlib.o pscom.o -L$(CAIRO_LIB) -lcairo -o $@
# PSVDRAW Make setup with errors:
#psvdraw: psvdraw.o graphic_output.o tlib.o pscom.o biglib.o
# $(COMP77) $(FFLAGS) $@.o graphic_output.o pscom.o tlib.o biglib.o -L$(CAIRO_LIB) -lcairo -o $@
pssect: pssect.o graphic_output.o pscom.o tlib.o biglib.o
$(COMP77) $(FFLAGS) $@.o graphic_output.o pscom.o tlib.o biglib.o -L$(CAIRO_LIB) -lcairo -o $@
pssect.o: pssect.f
$(COMP77) $(FFLAGS) -c pssect.f
psvdraw.o: psvdraw.f
$(COMP77) $(FFLAGS) -c psvdraw.f
pscom.o: pscom.f
$(COMP77) $(FFLAGS) -c pscom.f
tlib.o: tlib.f
$(COMP77) $(FFLAGS) -c tlib.f
biglib.o: biglib.f
$(COMP77) $(FFLAGS) -c biglib.f
graphic_output.o: graphic_output.c
$(CC) $(CFLAGS) $(INCL) -c -I$(CAIRO_INCLUDE) graphic_output.c
.c.o:
$(CC) $(CFLAGS) $(INCL) -c $<
.f.o:
$(FC) $(FFLAGS) $(INCL) -c $<
以下是令人討厭的fortran代碼:請注意,該問題就在程序開始時發生:
PROGRAM PSSECT
implicit none
include 'perplex_parameters.h'
integer jop0, ier99
logical vertex, output, first
character*100 fname, yes*1
integer iop0
logical debug
common / basic /iop0, debug
integer isec,icopt,ifull,imsg,io3p
common/ cst103 /isec,icopt,ifull,imsg,io3p
c----------------------------------------------------------------------
c Look for the "debug_yes" file to turn on debugging messages
PRINT *,'Pre-PSOPEN1'
call psopen ('plot2')
PRINT *,'Post-PSOPEN1'
這是被調用並產生錯誤的C代碼的一部分:
char dmh_debug = 0;
#define DEBUGPRINT(x) if (dmh_debug) {printf x;};
void psopen(char *fname, int fnamelen) {
printf("Debug opened\n");
char *outFileName;
char outputType[255];
char pageWidthString[255];
char pageHeightString[255];
/* Set debug status based upon presence of file named 'debug_yes' in directory */
FILE *debugFile = fopen("debug_yes", "r");
if (debugFile == NULL) {
dmh_debug = 0;
} else {
dmh_debug = 1;
}
fclose(debugFile);
dmh_debug = 1;
DEBUGPRINT(("Debug closed\n"));
fname[fnamelen]='\0';
fname = trim(fname);
outFileName = malloc((strlen(fname) + 50) * sizeof(char));
strcpy(outFileName, fname);
DEBUGPRINT(("Found file name:%s of length: %lu\n", fname, strlen(fname)));
[...]
pnr-rethington:source dave$ ./pssect
Pre-PSOPEN1
Debug opened
Segmentation fault
如果鏈接未使用的代碼觸發了問題,則可能表明在某個地方(在Fortran代碼或C代碼中)您正在覆蓋不應該覆蓋的內存。 嘗試在Valgrind下運行已編譯的程序-它應有助於查明發生這種情況的位置。
我仍然懷疑您在Fortran和C之間的某些調用有問題,從而導致不一致。 你怎么打電話? 我認為最可靠的方法是使用ISO C綁定向Fortran指定應如何調用C例程。
或者,您可以考慮具有Fortran界面或綁定的圖形包。 然后,您將不必在接口上工作,因為Fortran調用或Fortran接口已經存在。 我一直在使用DISLIN。 另一種可能是PLplot。
使用當前方法,我建議檢查C例程入口處的參數,以確保它們正確。
您正在使用單個參數從Fortran調用psopen,並且C例程需要兩個參數。 也許您的Fortran編譯器在每個字符串之后添加字符串的長度作為尾隨參數。 或者,也許您很幸運,但是第一次嘗試時,它恰好以C例程在堆棧中找到的“隨機”值工作。 在第二種情況下,在另一種情況下,可能會發生特殊的崩潰。 充其量,這是連接Fortran和C的一種不可移植的方法。您可以嘗試在Fortran調用中添加整數長度,然后看看會發生什么。 或打印或使用調試器在C例程的入口處查看第二個參數的值。
ISO C綁定效果更好。 許多編譯器(例如gfortran> = 4.3,ifort)都支持它,並且提供了一種定義的和可移植的連接Fortran和C的方式。您可以在Fortran代碼中指定一個“接口”,以便Fortran編譯器可以為Fortran生成正確的指令。打電話。
不過,使用已經提供了Fortran接口的繪圖程序包可能會更容易。
我從您的make文件中注意到您正在使用gfortran。 gfortran(> = 4.3)和gcc的組合支持ISO C綁定。 (Fortran 2003的一部分。)如果包括接口示例並使用兩個參數調用psopen,則它應該可以工作。 該接口進入Fortran程序的聲明,並且是C例程psopen的Fortran描述。 不能保證,因為我尚未測試過……字符串是一種特殊情況-您將Fortran程序中的縮放器字符串與接口中的字符串數組進行匹配,因為C參數是一個字符數組或一個指向字符
interface To_psopen
subroutine psopen ( fname, fnamelen ) bind (C, name="psopen")
use iso_c_binding
implicit none
character (kind=c_char, len=1), dimension (100), intent (inout) :: fname
integer (c_int), value, intent (in) :: fnamelen
end subroutine psopen
end interface To_psopen
在調試器( gdb
)下運行應該告訴您segfault發生在哪里。 用-O0 -g
編譯所有代碼以獲取准確的信息。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.