Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Fortran + C + commons in f77 part Question, + g77

1 view
Skip to first unread message

Deutscher

unread,
Apr 5, 1996, 3:00:00 AM4/5/96
to

Hi,
I have an odd little question regarding programmes combining modules
in fortran and C, and the usage of common blocks.
I manage to link and run everything and get the output I expect, but
I am surprised I actually do. Here is a little code segment, from memory and
just to illustrate my question:

C: main programme part to which f77 subroutines / functions are linked

double do_some_stuff(double t) {
double y;
y = f77func_(&t); /* append underscore and pass address of t to f77
function */

return (y);
}

int main(void) {
double t, y;

initvectors(); /* in external fortran code, initializes
the vectors w and x which are just used by
the fortran code see below */

t = get_t(); /* formal input routine to get t, not important here */

y = do_some_stuff(t); /* calculates some stuff, calling routines from the
main C programme and one routine from the
fortran code */
printf("%g %g\n", t, y);
return(0);
}


F77: the calculating subroutines

subroutine initvectors() ! initalize data
integer mw
parameter(mw=100)
double precision x(1:mw)
double precision w(1:mw)
common x,w ! <-- no SAVE here

call gauleg(-1.0d0,1.0d0,x,w,mw) ! initialize x and w, external

return
end

function f77func(t) ! calculate
implicit none
double precision f77func, t

integer mw ! common block from above
parameter(mw=100)
double precision x(1:mw)
double precision w(1:mw)
common x,w

double precision s
integer l

s = 0.0d0
do l = 1, mw
s = s + x(l)*w(l) ! something like this ...
enddo

f77func = s
return
end

On the Sun this works, and all is well, even though I forgot to
SAVE to common block between leaving initvectors() and entering
f77func().
That I understand: On the Sun I use f77, which accoring to the man page
initializes uninitalized variables to zero and saves variables between
subprogram calls, unless specifically told not to (via compiler options).
There I am not surprised my programme works.

Now I did the same thing under OS/2 using g77, which has been a VERY
GOOD THING for me lately (indeed, also today, it produced proper results
in agreement with the DEC fortran compiler where the Sun compiled code
generated garbage; that was in another code). Here I expected above code to
fail since I didn't specify -finit-local-zero and variables are by default
not saved. I was very surprised that the results agreed completely.

Now, I am wondering:
* Are there specific rules regarding unnamed common
blocks, even when they are not declared in a main programme block?
(either in the standard and hence in g77, or just in g77, or ?)
* does data get stored when things linked with foreign modules?
* Why does that work?

Mind you, I am not complaining at all, I just want to understand.

Thank you very much for ideas! Kind regards. Stefan


--
==========================================================================
Stefan A. Deutscher, s...@utk.edu, (001)-423-[522-7845|974-7838|574-5897]
home^ UTK^ ORNL^
==========================================================================
If there is software you'd like to have in a native version, visit the:
OS/2 E-mail Campaign Page http://www.andrews.edu/~boyko/email.html
--------------------------------------------------------------------------

Deutscher

unread,
Apr 5, 1996, 3:00:00 AM4/5/96
to

Following up to my own question I append below the ultimate answer I
got from Craig Burley (the g77 man for those who don't know). A short
summary: Unnamed COMMONS are always SAVEd as per the Standard, and on most
implementations also the named ones will be, even though that is not
required. (Indeed, I tried it with a named one, and SAVEd or not, the results
were the same). Cheers! Stefan

Deutscher (s...@utkux.utcc.utk.edu) wrote:

: Hi,

: return (y);
: }


: F77: the calculating subroutines

: return
: end


From bur...@gnu.ai.mit.edu Fri Apr 5 02:05 EST 1996

[...]


>* Are there specific rules regarding unnamed common
> blocks, even when they are not declared in a main programme block?
> (either in the standard and hence in g77, or just in g77, or ?)

Yes, blank (unnamed) common is _always_ "SAVEd". Also, it is
invalid to specify initial values for it (e.g. DATA). And, it
is okay for program units to declare unnamed common as having
differing sizes. Those are, offhand, the three things I can think
of that distinguish unnamed common from named common (which
can be unSAVEd or explicitly SAVEd, can have initial values
[set only in BLOCK DATA, but few compilers actually implement
that restriction], and must have program-wide agreement on
their sizes [many compilers can't or won't implement this
restriction because their linkers can't or won't; others have
linkers that enforce it strictly, I think]).

>* does data get stored when things linked with foreign modules?

If you mean does g77 somehow know, or generate code to determine,
if non-Fortran code is involved, the answer is no. [...]

>* Why does that work?

Because It's Standard. ;-)

>Mind you, I am not complaining at all, I just want to understand.

That's fine.

Now, make the common _named_, and you have a program that is
not as standard-conforming as the previous. (Shades of grey
here, since you're linking in C. ;-)

However, few modern Fortran compilers actually default to
_not_ SAVEing named common areas anyway, so you'd probably
get away with it anywhere you tried it. The application of
SAVE to common harkens back to the days of overlays (limited
memory), the idea being that if all the program units were
forced by the standard to agree whether a (named) common
block was SAVEd, a compiler could safely choose to replace
static allocation of an entire unSAVEd common block with
static allocation of just a _pointer_ to it in heap storage
(initialized to "nil", meaning no storage allocated). Then,
each procedure's code would start with code saying "if common
/FOO/'s static point is nil, set it to malloc(sizeof(/FOO/));"
in vaguely C-like notation. Also, the procedure invocation
that actually allocated space for the common area would
also be responsible for freeing it before returning to its
caller. (In gcc/C-speak, this is perhaps best done using
alloca instead of malloc; i.e. treat the unSAVEd named
common as an automatic array that is allocated only
when a static pointer is nil, and that static point
is used to access it.)

That way, when no "active" (called but not yet returned)
procedure invocation existed that made mention of an unSAVEd
named common area, hardly any memory would be wasted on it;
so several distinct "libraries" of procedures each sharing
their own, distinctly named, 100MB common area would, as long
as they never called a procedure in one of the other sets
(and this is characteristic of the way some libraries are
used by many applications), use only 100MB to hold _all_
their common areas -- as long as they did not need these areas
to hold values between application-level calls to the library
(e.g. temporary storage areas, such as buffering, used by
many procedures in a library but not needed when the library
is not actually active during the program's run). With
the default model of assuming SAVE, three such distinct
sets of library procedures would waste 300MB of memory on
their (possibly inactive) common areas!!

So, the feature of dynamically allocating unSAVEd common
areas is not a bad one at all.

g77 could actually do this if I spent about three days or
so on it, but there's no way it'd be the default behavior,
and nobody's asked for it yet, and I'd probably make them hire
me to do it...but it isn't rocket science.

I think the reason this sort of thing isn't needed any
longer is that only _modern_ Fortran code actually wants
to dynamically allocate _large_ chunks of memory; and
instead of using unSAVEd common to express that, they
use modern constructs like Cray or F90 pointers, which
g77 should someday support. (It's kind of strange to
think that, although much old Fortran code still can't
quite run as fast on today's desktop PCs as it did on its
original mainframes despite progress in CPU power --
though I'm not so sure about this -- there's not
likely to be any g77/Linux user who would run out of RAM
running that old Fortran code. The now-measley 16MB
I have in my system is more than many old, yet fast,
Fortran machines had in _total_ random-access storage
-- RAM/code and disk/drum included!!)

tq vm, (burley)

Roy McCammon

unread,
Apr 5, 1996, 3:00:00 AM4/5/96
to
Common is inherently static.
Once your initvectors() routine initialized the vectors,
they stayed initialized.

Opinions expressed herein are my own and may not represent those of 3M.

fair...@sldb4.slac.stanford.edu

unread,
Apr 6, 1996, 3:00:00 AM4/6/96
to
In article <4k42kh$6...@dawn.mmm.com>, rbmcc...@mmm.com (Roy McCammon) writes:
> Common is inherently static.
^^^^^^^^^^^^^^^^^^^^^^^^^^^

Not true. Perhaps a common implementation strategy, but the
Standard says nothing about it. Especially in the absence of a SAVE
statement (except that blank common is always saved). SAVE can be
implemented in a number of ways, and COMMON can be implemented on
the stack in such a way that once a common goes out of scope, all
its variable become undefined.

> Once your initvectors() routine initialized the vectors,
> they stayed initialized.

Only because the implementation (g77 this time?) chooses to do
so, not because of the Fortran standard.



> Opinions expressed herein are my own and may not represent those of 3M.

Indeed. If possible, would you please stop posting mis-
information (of which there's been quite a bit lately)? Thanks.

-Ken
--
Kenneth H. Fairfield | Internet: Fair...@Slac.Stanford.Edu
SLAC, P.O.Box 4349, MS 46 | DECnet: 45537::FAIRFIELD (45537=SLACVX)
Stanford, CA 94309 | Voice: 415-926-2924 FAX: 415-926-3515
-------------------------------------------------------------------------
These opinions are mine, not SLAC's, Stanford's, nor the DOE's...

Roy McCammon

unread,
Apr 8, 1996, 3:00:00 AM4/8/96
to
Thanks for the illumination.

Loren Meissner

unread,
Apr 8, 1996, 3:00:00 AM4/8/96
to
>Common is inherently static.

>Once your initvectors() routine initialized the vectors,
>they stayed initialized.

There is a bit more to the story than this, as regular readers
of this newsgroup know.

F77: "Execution of a return statement ... causes all entities
within the subprogram to become undefined except for ... initially
defined entities that have neither been redefined nor become
undefined ..."

F90: All variables that are initialized automatically have the
SAVE attribute, which is approximately equivalent to STATIC.

--Loren Meissner

Roy McCammon

unread,
Apr 9, 1996, 3:00:00 AM4/9/96
to
When I use named common, I use the following anti-bugging procedure:

The named common statement, explicit type declarations for every
variable, and explicit dimensions (usually using parameter statements)
for every variable and descriptive comments for every variable are placed
in a separate file. I usually use the suffix .cmm

Everywhere in my routines that I want access to that named common, I
include the above mentioned file.

Advantages:
1. If I need to make a change (I'll be adding SAVE ),
I only make it in one place.
2. Every instance of that named common has the same size and
variable boundries.
3. Every variable has the same name in each routine.

Disadvantages:
1. The common statement is not visible in the source file. You may
open a second window to view it. Sometimes I tempararily copy the
file into my source and comment it out, so I can veiw it. I remove
it later, because there is no way to keep the comments automatically
updated.
2. My compiler emits somewhat ambiguous messages about where it was
when it finds an error while it was in an included file.
3. Same as advantage number 3. You may not want the same names. You
may inadvertently use the name for something else. There is plenty
of rope. If you had ten instances of a particular common statement
and wanted it to be different in one of them, you could still do that.

fair...@sldb4.slac.stanford.edu

unread,
Apr 9, 1996, 3:00:00 AM4/9/96
to
In article <4ke3fm$a...@dawn.mmm.com>, rbmcc...@mmm.com (Roy McCammon) writes:
> When I use named common, I use the following anti-bugging procedure:
>
> The named common statement, explicit type declarations for every
> variable, and explicit dimensions (usually using parameter statements)
> for every variable and descriptive comments for every variable are placed
> in a separate file. I usually use the suffix .cmm
>
> Everywhere in my routines that I want access to that named common, I
> include the above mentioned file.

Agreed. This is the most rational, safest way to use COMMON.

> Advantages:
> 1. If I need to make a change (I'll be adding SAVE ),
> I only make it in one place.
> 2. Every instance of that named common has the same size and
> variable boundries.
> 3. Every variable has the same name in each routine.
>
> Disadvantages:
> 1. The common statement is not visible in the source file. You may
> open a second window to view it. Sometimes I tempararily copy the
> file into my source and comment it out, so I can veiw it. I remove
> it later, because there is no way to keep the comments automatically
> updated.
> 2. My compiler emits somewhat ambiguous messages about where it was
> when it finds an error while it was in an included file.

I think both 1. and 2. are "quality of implementation" issues.
Many editors allow you to simultaneously view two or more separate
files, or regions of the same file. If your system's debugging
environment doesn't handle include files very well, complain to the
vendor. I can give you an "existence proof" of at least one system
where neither 1. nor 2. are a problem.

> 3. Same as advantage number 3. You may not want the same names. You
> may inadvertently use the name for something else. There is plenty
> of rope. If you had ten instances of a particular common statement
> and wanted it to be different in one of them, you could still do that.

This can be averted in two (roughly equivalent) ways. (A)
Declare _all_ variables in the subroutine, don't depend on Fortran's
default implicit typing, nor on "traditional" implicit typing, e.g.,
IMPLICIT DOUBLE PRECISION (R-V). (B) Use a compiler that supports
IMPLICIT NONE, and therefore, forces (A).

If you declare all variables in every subprogram, and you've
declared all variables in COMMON in the include file, your compiler
will (or should!) flag an error for declaring the same variable
twice, even if the declaration is the same (although one would think
it would be different more often than not).

Deutscher

unread,
Apr 10, 1996, 3:00:00 AM4/10/96
to

Comming from and still using Pascal (and being determined to continue
that) I used to do it quite similar, my first line in any subroutine,
function, or main programme block is 'implicit none' :-)
Anyway, for me 'literate programming' has turned out to be a more
productive solution than different include files and the like.
Literate programming techniques combine documentation (most of the time,
but not automatically required, in (La)TeX) and code in one file from
which both the well documented code and the compilable sources can be
generated. That is one more step in a makefile.
So, for a common block, say, for Gauss-Legendre integration, I just
declare that once and for all, say as

@<Common block for Gauss--Legendre ... @>=
integer mw
parameter (mw = 100) ! play with this
double precision x(1:mw) ! nodes \dots
double precision w(1:mw) ! \dots\ and weights
common x, w

and call it everywhere it is needed by it name, say

subroutine InitGauleg()
@<Common block for Gauss--Legendre ... @>
call gauleg(-1.0d0, 1.0d0, x, w, mw)
return
end

Advantages: readable, consistent documentation, consisent source
Disadvantage: I have to learn web one afternoon. Others are
frightened because ''it don't look like fortran no more at first ''

Kind regards! Stefan


Roy McCammon (rbmcc...@mmm.com) wrote:
: When I use named common, I use the following anti-bugging procedure:

: The named common statement, explicit type declarations for every
: variable, and explicit dimensions (usually using parameter statements)
: for every variable and descriptive comments for every variable are placed
: in a separate file. I usually use the suffix .cmm

: Everywhere in my routines that I want access to that named common, I
: include the above mentioned file.

: Advantages:


: 1. If I need to make a change (I'll be adding SAVE ),
: I only make it in one place.
: 2. Every instance of that named common has the same size and
: variable boundries.
: 3. Every variable has the same name in each routine.

: Disadvantages:
: 1. The common statement is not visible in the source file. You may
: open a second window to view it. Sometimes I tempararily copy the
: file into my source and comment it out, so I can veiw it. I remove
: it later, because there is no way to keep the comments automatically
: updated.
: 2. My compiler emits somewhat ambiguous messages about where it was
: when it finds an error while it was in an included file.

: 3. Same as advantage number 3. You may not want the same names. You


: may inadvertently use the name for something else. There is plenty
: of rope. If you had ten instances of a particular common statement
: and wanted it to be different in one of them, you could still do that.


: Opinions expressed herein are my own and may not represent those of 3M.

--

0 new messages