Operating System - OpenVMS
1753767 Members
5930 Online
108799 Solutions
New Discussion юеВ

Re: Fortran and C alignment

 
SOLVED
Go to solution
Jenwae
Advisor

Fortran and C alignment

Hi,

I have searched the KB, but did not find what is needed.

We have a legacy application written in Fortran, that we are converting to C.
For unit testing purposes (also divide-and-conquer), we typically convert a process to C, and leave the rest in Fortran. This will require our converted C process to call certain modules that are in Fortran, that is, calling Fortran from C (sharing programs in mixed languages). Our problem now lies in the alignment especially for COMMON blocks (shared memory).

Our legacy uses many COMMON, and we have "successfuly" map the global section in C to the COMMON in Fortran. However, we found out (through compile maps) that the global section size in C does not match the one in Fortran, and this will cause issues at run-time. This may be caused by alignment.

Using MMS, we built the FOrtran using:
FORTRAN/noopt/float=ieee_float/align=(commons=(natural,multilanguage),records=natural)

For C:
cc/noopt/standard=C99/member_alignment/extern_mode=common_block/float=ieee_float


We think the build commands are correct, as previously, for Fortran, the records=packed is used.

However, because of the way our legacy was coded, the build commands may not cure the problem. In a typical declaration, the different data types are interspersed, as opposed to clean ordering. For eg,

INTEGER*2 c1w
INTEGER*4 c2l
INTEGER*2 c3w
REAL*8 costr
INTEGER*2 c4w

COMMON /xyz/ c1w,c2l,c3w,costr,c4w

Is there a way to resolve this alignment issue without having to change the legacy code (there are countless of such COMMON declaration)?

Thank you very much.
24 REPLIES 24
Hoff
Honored Contributor

Re: Fortran and C alignment

If I understand the question and in the C code, you can control alignment at the structure level with the following:

#pragma member_alignment save
#pragma [no]member_alignment
whatever data you are looking to control
#pragma member_alignment restore

The pragmas can also be used to control ref-def and related external addressing, as well. When working with a common, these are key. See #pragma extern_model et al.

Personally, I'd look to ditch the Fortran common stuff entirely going forward. Global sections have various advantages, and the installed commons have various disadvantages.

Though you're probably past this stage, here's some stuff I wrote up on working with Fortran commons in C code, if that's of interest:

http://h71000.www7.hp.com/wizard/wiz_2486.html
Steven Schweda
Honored Contributor

Re: Fortran and C alignment

Or manually pad the C structures so that the
(real) C data align with the Fortran data.

Someone had to create the C structures for
the new C code, right? How was that done?
(I see your Fortran example code. I don't
see the corresponding C code.)
Joseph Huber_1
Honored Contributor

Re: Fortran and C alignment

Assuming the order of variables in the Fortran common and the C structures are the same, then the length of the Psects is determined by padding.
Specify /PSECT_MODEL=MULTILANGUAG in CC, corresponding to /align=commons=(natural,multilanguage) in Fortran, to get the same Psect size.
http://www.mpp.mpg.de/~huber
Joseph Huber_1
Honored Contributor

Re: Fortran and C alignment

BTW,
if compiled with NOMULTILANGUAGE, DECC still padds the Psect to a multiple of 8 bytes, while Fortran does no padding at all in this case.

So to mix languages always align natural AND multilanguage.
http://www.mpp.mpg.de/~huber
Robert Gezelter
Honored Contributor

Re: Fortran and C alignment

Jenwae,

Needless to say, using the compiler listings to VERIFY that the variable alignments actually are correct is an excellent idea.

Both compilers have various listing options. A careful review of actual printed variable assignments (offsets into structures) would be sound procedure.

- Bob Gezelter, http://www.rlgsc.com
Jenwae
Advisor

Re: Fortran and C alignment

Hi All,

Thank you so much for the replies.

Hoff, I almost did that but the application is huge, and to insert that pragma section for each module is not too practical. Also, trying the pragma directives on one individual module reveals that it does not work (seemingly).

Steve:
The real issue is that the section for Fortran is SMALLER than the C. I want to avoid changing anything on the legacy Fortran.
Also, when I used the option COMMONS=(NATURAL, RECORDS=NATURAL), instead of the original RECORD=PACKED, the FOrtran section is still SMALLER than C, which I don't understand why.

In the example below:

INTEGER*2 c1w
INTEGER*4 c2l
INTEGER*2 c3w
REAL*8 costr
INTEGER*2 c4w

the C equivalent (converted automatically) by a translator) is:

short int cw1
long int c21
short int c3w
double costr
short int c4w

For every short int, the C compiler will pad an additional 2 bytes (to make it natural-aligned). However for Fortran, it still maintain a Integer*2 (without padding) even after using RECORDS=NATURAL

Joseph:
I tried both multi and nomulti, and all opther option combination...to no avail.

Robert:
I linked with the option /map. From the map, I could see the section for C is always bigger than that of Fortran for that particular global sections.

Steven Schweda
Honored Contributor
Solution

Re: Fortran and C alignment

> #pragma member_alignment save
> #pragma [no]member_alignment
> whatever data you are looking to control
> #pragma member_alignment restore

This seems to work for me. Did you try it?

alp $ type cs.c
#include

main()
{
struct
{
short int cw1;
long int c21;
short int c3w;
double costr;
short int c4w;
} cs;

printf( " cw1: %2lld.\n", (long long) &cs.cw1- (long long) &cs);
printf( " c21: %2lld.\n", (long long) &cs.c21- (long long) &cs);
printf( " c3w: %2lld.\n", (long long) &cs.c3w- (long long) &cs);
printf( " costr: %2lld.\n", (long long) &cs.costr- (long long) &cs);
printf( " c4w: %2lld.\n", (long long) &cs.c4w- (long long) &cs);
printf( " size: %2d.\n", sizeof cs);
}
alp $ cc cs
alp $ link cs
alp $ run cs
cw1: 0.
c21: 4.
c3w: 8.
costr: 16.
c4w: 24.
size: 32.

So, the default is 4-byte alignment, but:

alp $ type cs2.c
#include

main()
{
#pragma member_alignment save
#pragma nomember_alignment
struct
{
short int cw1;
long int c21;
short int c3w;
double costr;
short int c4w;
} cs;
#pragma member_alignment restore

printf( " cw1: %2lld.\n", (long long) &cs.cw1- (long long) &cs);
printf( " c21: %2lld.\n", (long long) &cs.c21- (long long) &cs);
printf( " c3w: %2lld.\n", (long long) &cs.c3w- (long long) &cs);
printf( " costr: %2lld.\n", (long long) &cs.costr- (long long) &cs);
printf( " c4w: %2lld.\n", (long long) &cs.c4w- (long long) &cs);
printf( " size: %2d.\n", sizeof cs);
}
alp $ cc cs2
alp $ link cs2
alp $ run cs2
cw1: 0.
c21: 2.
c3w: 6.
costr: 8.
c4w: 16.
size: 18.

If that's not what you want, then what _do_
you want? One of us seems to be missing
something. You or I?
Hoff
Honored Contributor

Re: Fortran and C alignment

I've used the exact technique and the exact construction with the compiler pragmas. It works in all the cases I've tried. The pragma-based approach also works nicely in larger applications, when module-wide settings for non-native alignments can be detrimental to application performance.

If you're repeating structures (eg: a C array) within the common, then you can get padding at the end of the structure.

Use the debugger. Examine memory. Figure out what is going on.

And chuck the common-based design out the airlock at your first opportunity; position-independent designs are much more flexible.
Joseph Huber_1
Honored Contributor

Re: Fortran and C alignment

>>
Joseph:
I tried both multi and nomulti, and all opther option combination...to no avail.

What compilers/system versions do You have ?

Mine, starting with DECC 6.5, Fortran 7.2, VMS 7.3-1 and upwards (Alpha and Itanium) both Fortran and C commons are exactly the same length (32 bytes), and the individual fields as Steven showed, if compiled with natural alignement and multilanguage padding.
http://www.mpp.mpg.de/~huber