Intel® Fortran Compiler
Build applications that can scale for the future with optimized code designed for Intel® Xeon® and compatible processors.

two ISO_C_BINDING questions

newfortranuser
Beginner
1,645 Views

My boss dropped a bunch of old Fortran code on my desk. Some parts need to be ported to Intel Fortran and I need to find good options for interfacing with C++.

1. Are COMMON data interoperable? (Assuming interoperable types and dimensions)

2. Are there any runtime penalties for ISO_C_BINDING?

Thanks

0 Kudos
1 Solution
Steven_L_Intel1
Employee
1,645 Views

1. A comma before BIND in a procedure declaration is not correct syntax.

2. You do not have to (and in fact must not) name the COMMON variables in a BIND declaration - all that is required is that they be of interoperable type. So you might have:

[fortran]variables are multiply-defined

common /cdata/ a, b(-1:1), i
real(C_FLOAT) :: a, b
integer(C_INT) :: i
bind(C) /cdata/[/fortran]
This would correspond to a C struct named cdata. You can name the variables in the common block anything you please. Does this help?

View solution in original post

0 Kudos
12 Replies
Steven_L_Intel1
Employee
1,645 Views

COMMON blocks are interoperable with C EXTERN variables as long as all the variables are also "interoperable". Name the COMMON block in a BIND(C) declaration. Module variables are similarly interoperable.

No run-time penalty. I will comment that ISO_C_BINDING is a module with declarations. The term you want is "C interoperability features", of which ISO_C_BINDING is only a part.

0 Kudos
newfortranuser
Beginner
1,645 Views

Got it. Thank you!

And thanks for pointing out the difference between the module and the language feature.

0 Kudos
newfortranuser
Beginner
1,645 Views

Doctor Steve,

Thanks for your reply. I have a followup. I'm also referring to John Reid's New Features of Fortran 2003 and section 15.1 of the final committe draft of ISO/IEC FCD 1539-1:2004(E). Yawn. How exciting. :)

1. I see that IVF apparently does *not* want a comma after a routine name and before the BIND keyword. Is that correct?

2. I see (and have had some success) in making an *entire* COMMON block interoperable, by providing each of its members with an interoperable declaration *and* binding the *entire* common block, as in

! This compiles

common /com_data/ a, b(-1:1), i
real(C_FLOAT) :: a, b

integer(C_INT) :: i
bind(C) :: cdata

But what if I want to rename some or all members of the common block?

! This does NOT compile because the variables are multiply-defined

common /cdata/ a, b(-1:1), i
real(C_FLOAT) :: a, b
integer(C_INT) :: i

bind(C, NAME='a_iso') :: a
bind(C, NAME='b_iso') :: b
bind(C, NAME='i_iso') :: i

Ok, so I tried to get clever:

! This does NOT compile because equivalenced entities cannot be bind-entities

common /cdata/ a, b(-1:1), i
real(C_FLOAT) :: a, b
integer(C_INT) :: i

integer(C_INT) :: i_iso

equivalence (i, i_iso)

bind(C) :: i_iso

Ok, I'm pretty sure I could "hide" the name-change behind a function call. That would be essentially an accessor (get/set method) and would essentially negate a key benefit of ISO_C_BINDING because then there is stack management overhead when all I really wanted was a safe way for C++ to access the Fortran data.

And yes I could break the COMMON blcok into two COMMON blocks -- one which is bound and one which is not. But that would assume that some crazy old programmer didn't rely on "pointer arithmetic" within the original COMMON block, and that is *not* a safe assumption for what I'm staring at.

So to recap -- is there a no-stack-overhead way to share data using ISO_C_BINDING which allows me to selectively share just certain elements of a COMMON block, preferably with the ability to expose a different name on the C++ side?

Thanks for enduring my 20 questions.

0 Kudos
Steven_L_Intel1
Employee
1,646 Views

1. A comma before BIND in a procedure declaration is not correct syntax.

2. You do not have to (and in fact must not) name the COMMON variables in a BIND declaration - all that is required is that they be of interoperable type. So you might have:

[fortran]variables are multiply-defined

common /cdata/ a, b(-1:1), i
real(C_FLOAT) :: a, b
integer(C_INT) :: i
bind(C) /cdata/[/fortran]
This would correspond to a C struct named cdata. You can name the variables in the common block anything you please. Does this help?

0 Kudos
newfortranuser
Beginner
1,645 Views

Thanks, Steve.

That does help. I suppose for some people thevalue of iso_c_binding lies in not having to deal with calling conventions. That never scared me. I really had several similar different goals here:

1. Expose Fortran data to C without using the stack (otherwise, I'd just use mixed-language get/set calls).

... The iso_c_binding is perfect for this.

2. Expose some but not all entities of an existing COMMON block.

... I now see that exposing COMMON is all-or-nothing. Not even an EQUIVALENCE will trick it. That's unfortunate, because I dare not risk splittng legacy common blocks for which someone relied on contiguous storage and later used variable subscripts to cross "semantic boundaries" between COMMON elements. So now I have to choose between splitting the common block (and patchng the code) or exposing the whole common block to C.

3. Expose those entities to C with 'alias' names different from the actual entitity names.

>>> I am dealing with existing code, so renaming the COMMON members in a library of shared code. The fact that I can name the common element anythng I please does not mean that I may or should change them. Since locals can be exposed via an alias, I hoped the same would be true for gloabals. I do see how that could (in principle) bloat the symbol table, with multiple aliases having a single referent, but I don't think it would create any ambiguity.

Ok, your reply has told me what I can and cannot do. It's up to me to decide what is appropriate. Any impedance mismatch between the two is my problem. It's a small price to pay for not losing years of my life sitting on a committe to try and probably fail to get what I want. :)

Thanks, Steve!

0 Kudos
Steven_L_Intel1
Employee
1,645 Views
Perhaps pointers would help you here? I don't fully understand what you're trying to do.
0 Kudos
newfortranuser
Beginner
1,645 Views

Thanks, Steve. Apparently, my own thinking is fuzzy.

I see now that I can (duh!) name the members of my C struct whatever I like.

But now I'm having a linkage problem. According to the ASM outputs, IVF 11.1.054 is calling my common block _cdata and MSVC8 is calling my external structure ?cdata@@3Ucommon_cdata@@A. I would be grateful if you would take a quick look at the attached code (which is slightly busy) in which I think the key parts are as follows:

Fortran static lib has

COMMON /CDATA/

BIND(C,NAME='cdata') :: /CDATA/ !! I have tried this with and without the name, same behavior.

C++ has the main() and has (in global scope, outside all function declarations)

struct common_cdata
{ float a;
float b[2];
int i;
int j[10];

}; // matches CDATA in Fortran

extern struct common_cdata cdata;

The attached solution compiles but does not link. IDE is Visual Studio 2005. Target is ia32/debug. I am building usiing multithreaded debug libs, if that matters, but I have already taken care of /NODEFAULTLIBS:MSVCRTD.LIB

Also note that I have been successful in binding Fortran functions and calling them from C -- once I remembered to declare summy arguments with the VALUE attribute on the Fortran side. It's just the global data interop that has me stumped at this point.

Thanks in advance for any and all comments.

0 Kudos
newfortranuser
Beginner
1,645 Views

Sorry. I should mention that the linkage error is

ISO_Common.obj : error LNK2001: unresolved external symbol "struct common_cdata cdata" (?cdata@@3Ucommon_cdata@@A)

Thanks

0 Kudos
newfortranuser
Beginner
1,645 Views

Got it!!!!

The problem was that I declared the instance of the external struct type as

extern struct common_cdata cdata;

I changedit to

extern "C" struct common_cdata cdata;

(note the "C") and everything worked!

According to MSDN, the string-literal ("C" in this case) is *required*. So I don't know why my code compiled in the first place, because other evidence clearly showed that syntax like cdata.a was working as expected. Anyway, problem solved I think.

Thanks!

0 Kudos
IanH
Honored Contributor III
1,645 Views

The "C" literal is required in C++ if you want your global variable to have C linkage, which you do because that's the language (not C++) that fortran interoperates with via BIND(C,...).

Note that if you do start chopping up the common blocks, then module variables can be interoperable as well. As a general opinion, use of modules is vastly preferable to common blocks for new code. Issues with what some "crazy old programmer" might have done in terms of the layout of variables within the common block still apply.
0 Kudos
newfortranuser
Beginner
1,645 Views

Thanks IanH. Makes sense.

I was surprised that the MSVC++ compiler did not complain, because http://msdn.microsoft.com/en-us/library/0603949d%28VS.80%29.aspx implies that the string specifier is required (even though some their own examples on the same page omit it). I should have realized that it would default to C++ conventions.

I see what you mean about modules. Nice. I wish modules existed when this code was written!

Thanks

0 Kudos
TimP
Honored Contributor III
1,645 Views

I was surprised that the MSVC++ compiler did not complain, because http://msdn.microsoft.com/en-us/library/0603949d%28VS.80%29.aspx implies that the string specifier is required (even though some their own examples on the same page omit it). I should have realized that it would default to C++ conventions.

In C89 mode (e.g. source file .c), even MSVC doesn't mangle identifiers.
0 Kudos
Reply