2012-06-13 3 views
2

일부 라이브러리가 필요한 C++ 프로그램을 컴파일 중입니다. 이 라이브러리의 코드는 Fortran으로 작성되었으며 COMMON 블록을 포함합니다. 기본적으로 내가 좋아하는 뭔가를하고 있어요 :COMMON 문으로 Fortran 라이브러리를 포함한 C++ 컴파일

g++ -o main.cpp main lib1.a lib2.a 

Lib1.a 및 lib2.a은 포트란 코딩 :

gfortran -c -o lib1.a Code1.F 
gfortran -c -o lib2.a Code2.F 

그리고 모두가 같은 것을 포함하는 헤더 파일을 포함한다 :

double precision var1,var2 
double precision var3,var4 

common /block1/ var1,var2 
common /block2/ var3,var4 

COMMON 블록에 문제가있는 것 같습니다. 예를 들어 공통 변수 뒤에 변수의 순서를 변경하거나 새 변수를 추가하면 결과가 무작위로 일치하지 않게됩니다.

가능하면 COMMON 문을 사용해서는 안되지만이 경우 문제가 될지는 모르겠다.

답변

1

컴파일러 Fortran에 따라 변수 사이에 패딩이 삽입 될 수 있습니다. 어쩌면 포트란과 C++ 컴파일러는 이것에 동의하지 않을 수도 있습니다. 그냥 추측.

Fortran 코드를 변경하려는 경우 Fortran 컴파일러가 C 컴파일러의 규칙과 일치하는 코드를 생성하도록 지시하기 때문에 ISO C 바인딩을 사용하는 것이 도움이됩니다. http://software.intel.com/sites/products/documentation/hpc/compilerpro/en-us/fortran/lin/compiler_f/bldaps_for/common/bldaps_interopc.htm에 일반적인 블록 예제가 있습니다. 해당 예를 기반으로 :

use, intrinsic :: iso_c_binding 
real (c_double) :: var1, var2, var3, var4 
common /block1/ var1, var2 
common /block2/ var3, var4 
bind (C) :: /block1/, /block2/ 

더 많은 모델을 만들려는 경우 더 좋은 옵션은 모듈 변수입니다. 그러면 메모리의 레이아웃에 대해 걱정할 필요가 없습니다.

module global_vars 
use, intrinsic :: iso_c_binding 
real (c_double), bind (C) :: var1, var2, var3, var4 
end module global_vars 
+0

감사합니다. 그러나 나는 코드를 변경하는 것이 가장 간단한 해결책이라는 것을 확신하지 못합니다. 그 이유는 대부분 fortran 77로 작성된 거대한 코드이기 때문입니다. – user1453767

1

이 순서를 변경하는 것은 예상 된 후에 발생 중요하고 나쁜 일이다 COMMON 블록의 변수의 순서. 공통 블록이 사용되는 모든 곳에서 동일해야하며 을 C++ 프로그램에 포함합니다. 중요하지 않은 것은 변수에 주어진 이름입니다. 예 :

double precision a, b 
common /block1/ a, b 

을 그리고 또 다른 서브 루틴에서 당신은 할 수있다 : 하나 개의 서브 루틴에 당신은 할 수

double precision c, d 
common /block1/ c, d 

여전히 ac을 동일한 메모리 위치를 공유 할 것입니다. bd에도 동일하게 적용됩니다. 이것은 혼란을 야기 할 수 있으며 통상적 인 실행은 변수 공통 블록 선언과 공통 블록 선언을 모두 사용자가 수행 한 특정 공통 블록을 사용하는 모든 서브 루틴에 의해 include -d 파일에 저장하는 것입니다. 이제 모든 공통 블록에서 무언가를 변경하면 모든 서브 루틴이 변경된 것을 볼 것이며 모든 것이 예상대로 작동합니다.

문제는 변경된 공통 블록에 대응시키기 위해 해당 C 구조를 변경해야한다는 것입니다. 예 :

struct common_block1 
{ 
    double a; 
    double b; 
}; 
extern struct common_block1 block1_; 

(참고 : 오래된 포트란 컴파일러 bind(C) 속성 넣어를 지원하지 않는 내 보낸 각 식별자의 끝에서 밑줄 C/C에 있도록 ++ 당신이 가진 것

double precision a, b 
common /block1/ a, b 

는로 C에 해당 참조하는 block1

) block1_로 당신에게 일반적인 블록을 변경하는 경우 :

integer a 
double precision b, c 
common /block1/ a, b, c 

당신은 또한에 C 구조를 변경해야합니다 :

struct common_block1 
{ 
    int a; 
    double b; 
    double c; 
}; 

모든 것을 C와 포트란 컴파일러가 같은 메모리 정렬 규칙을 사용하여 모두 주어진. 정렬은 대개 컴파일러 옵션 (C/C++/Fortran) 및 유형 속성 (C/C++)을 사용하여 제어 할 수 있습니다. ISO_C_BINDING 사용 Fortran 모듈은 Fortran과 C에서 동일한 저장 공간 크기를 가진 유형을 사용하도록 보장 할 수 있습니다. 가장 큰 객체 (예 : 어레이, (DOUBLE) COMPLEX 개 변수, DOUBLE PRECISION 개 변수 등)를 공통 블록의 시작 부분에 넣고, 그 뒤에는 작은 물체 등이 뒤 따른다.

+0

매우 명확한 설명에 감사드립니다. 그러나 사실 내 C++ 프로그램은 공통 블록에있는 변수를 사용하지 않습니다. 그래서 나는 약간 당혹 스럽다. 그럼에도 불구하고 내가 보여 준 것처럼 내 C++ 코드에서 블록을 선언해야합니까? – user1453767

+0

아니요, 그러지 마십시오. 하지만 코드를 확인하는 것이 좋습니다. 다른 방법으로 정의 된 공통 블록이 있거나 포트란 코드에 다른 오류가있을 수 있습니다 (예 : 스칼라 변수가 배열로 처리됨). –

0

나는 버그의 기원을 이해한다고 생각한다. 헤더 파일을 포함하여 라이브러리 lib1.a를 먼저 컴파일했습니다. 그렇다면 실제로이 헤더 파일 (특히 공통 블록)을 수정하고 라이브러리 lib2.a를 컴파일했습니다. 이것은 다른 라이브러리에있는 두 개의 공통 블록 사이에 안개가 생기는 것은 논리적 인 것처럼 보입니다 ...

나는 이것을 자세히 검토 할 것이지만, 이것이 설명 일 것이라고 확신합니다. 귀하의 조언을 주셔서 감사합니다, 그것은 모든 것을 확인하는 데 도움이되고 이것이 내가 해결책을 찾은 방법입니다!

관련 문제