The __fortran calling convention isn’t the calling convention used by FORTRAN

Although the Microsoft C compiler supports a calling convention called __fortran, that's just what the calling convention is called; its relationship with the FORTRAN programming language is only coincidental. The __fortran keyword is now just an old-fashioned synonym for __stdcall.

Various FORTRAN compilers use different calling conventions; the one I describe here applies to the now-defunct Microsoft Fortran PowerStation.

Fortran Powerstation pushes parameters on the stack right-to-left, with callee-cleanup. (So far, this matches __fortran aka __stdcall.) Function names are converted to all-uppercase, with an underscore at the beginning and @n appended, where n is the number of bytes of parameters. (This still matches __stdcall aside from the uppercase conversion.)

As for how the parameters are passed, well, that's where things get weird. FORTRAN natively passes all parameters by reference. This is the source of a famous classic FORTRAN bug known as constants aren't.

      CALL MAGIC(1)
      PRINT *, 'According to the computer, 3 + 1 is ', ADDUP(3, 1)

      ADDUP = I + J

C     What does this subroutine actually do?
      I = 9


(It's been a long time since I've written a FORTRAN program, so I may have gotten some of the details wrong, but any errors shouldn't detract from the fundamental issue.)

When you run this program, it says

According to the computer, 3 + 1 is 12

How did that happen? We called a function that adds two numbers together, and instead of getting 4, we get 12?

The reason is the subroutine MAGIC: We passed it the constant 1, and since all FORTRAN parameters are passed by reference, the assignment I = 9 modifies the constant 1. In C:

int One = 1;
int Three = 3;
int Nine = 9;

void Magic(int *i) { *i = Nine; }
int AddUp(int *i, int *j) { return *i + *j; }

void main()
 printf("According to the computer, 3 + 1 is %d\n",
        AddUp(&Three, &One));

Since Magic modified the constant One, any further use of the constant 1 ends up using the value 9! (According to the FORTRAN standard, modifying a constant results in undefined behavior.)

Okay, back to calling conventions. Other significant differences between C and FORTRAN: In FORTRAN, array indices begin at 1, not 0, and arrays are stored in column-major order rather than row-major as in C.

COMPLEX variables in FORTRAN are stored as two floating point numbers (corresponding to the real and imaginary components).

Functions which return COMPLEX or CHARACTER*(*) are internally rewritten as subroutines where the location to store the return value is passed as a hidden first parameter. (This is analogous to how C returns large structures.)

The final commonly-encountered weirdness of FORTRAN is that CHARACTER*n data types (which are used to hold strings) are passed as two parameters: The address of the character buffer, followed by the size of the buffer (n). Note that FORTRAN CHARACTER*n variables are fixed-length; if you assign a string shorter than the buffer, it is padded with spaces. There is no null terminator.

Anyway, I sort of got carried away with the FORTRAN calling convention. It's definitely more complicated than just sticking __fortran in front of your function. But at least the __fortran keyword takes care of the part that can't be expressed in C. The rest you can manage on your own.

Comments (36)
  1. Mott555 says:

    FORTRAN is way before my time so thanks for the article, I actually find that fascinating! But I bet it leads to some really strange and hilarious bugs in actual FORTRAN applications, especially if newbie programmers are involved who don't understand the calling conventions and are used to more modern languages.

  2. Timbo says:

    The shocking fact for me isn't that they pass the "constants" by reference.

    It is that the "1" that seems to be a numeric literal in the eyes of a C programmer, I could only describe as "implicitely defined local(?) variable with the name of the literal, pre-initialized to its numeric value".

  3. Anonymous Coward says:

    With every article on the subject of string handling I lose more respect for the C designers' string handling decision. This article is no exception.

    On the other hand, the ‘constants aren't’ bug is pretty atrocious. Although it does bring back fond memories of a similar issue in some C compilers concerning string constants.

  4. Tim says:

    If you really want to complicate things, check out the FORTRAN EQUIVALENCE statement. It allowed you to say that a bunch of variables shared the same memory. So you could change a variable of one type and see it reflected in a variable of another type that had been made "equivalent". APL, now that was a language :)

  5. NB says:

    Ok, now I understand the second part of Osborn's Law: "Variable's won't, Constants aren't" :)

    But what about the first part? Where does that come from?

  6. James Curran says:

    @Joseph Koss: Actually, the default base in Basic is 0.  It just most basic programs just ignore the zero element.  

    In the first Fortran system I had to work on, I run into a real-world MAGIC() function.

    If was the applications standard formatted output routine it took a variable number of pairs of parameters, e.g., something like:

      PRINT(100, "first num:",  101, X,   901, 30, 100, "Second Num:", 102, Y,  902, pos, 901, 132-pos, 100, "more text")

    Each pair would be a code, followed by the data to act on.  In this example, "100" means "Print next parameter as text", 101 means "format as integer (aka fixed)", & 102, "format as float".  The interesting bit come with the 900 codes.  901 would mean "skip to the column position given by next parameter", and 902 means "set next parameter to the current column position".  Hence a simple mistake of 902 where you meant 901 could redefine a constant.  (of course, as the problem wouldn't show up until the next time you used that particularly number, have fun debugging that!)

    (nit-pickers will of course note that there is a difference between fixed & integer)

  7. SimonRev says:

    @Tim:  Didn't you just describe a C/C++ union (while it may be undefined to set one union member then read another, your description of Fortran's EQUIVALENCE sounds like the standard implementation of that behavior in a union)

  8. Ian says:

    In general, you call Fortran functions in a DLL from some other language. It would be pretty perverse (though perfectly possible) to write a front-end GUI in Fortran that calls number-crunching functions in a Visual Basic DLL…

    Anyway, I generally find it is much, much easier to force the Fortran compiler to use a 'normal' calling convention for the functions exported from the DLL. It means a little bit of extra work sometimes marshalling parameters of these exported functions in the Fortran code, but it saves a lot of headaches in the long run.

  9. James Curran says:

    > With every article on the subject of string handling I lose more respect for the C designers' string handling decision.

    @Anon,  Actually, it wasn't that bad, for the time (i.e., the time of extremely low RAM and disk sizes.).

    Note that because some strings would go beyond 255 characters, if a size is used, it would have to be at least 16-bits for ALL strings.  With ASCIIZ string, all strings can use an 8-bit terminator.  Further, most uses of a string involve iterating through it anyway, so having a separate size isn't buying you much.

  10. James Curran says:

    > Fortran's EQUIVALENCE sounds like the standard implementation of that behavior in a union

    @SimonRev Only accidentally.  The actually GOAL of EQUIVALENCE is to make the variables public, i.e., this list of variables I use in this module are the same as that list of variables I use in that module.

    So, it's not like a union where you have an int & a pointer. Imagine a union made up of two structs (each with many elements) The names of the elements aren't expected to match — but the types are. It's only if you screw up the order does freakiness occur.

  11. AsmGuru62 says:

    FORTRAN is old, so memory for compiled binaries was kind of scarce. That is why constant '1' from call to MAGIC has the same address as constant '1' passed to ADD function. FORTRAN compiler simply remembers the VALUE of the constant, so when another such constant appears in code — it simply finds the first instance and re-uses the same address instead of reserving more memory. C compiler can do something similar with constant strings, but it is optional. I wonder if that code will produce same results in modern FORTRAN compiler, say Intel Fortran.

  12. Boyd says:

    Wow, that brings back memories (and some nightmares as well).  I had to write a C interface wrapper around a third party FORTRAN library back in the dark ages.  It was all sorts of fun trying to figure all of these things out without any documentation on the calling convention.  The fact that the machine we were running was an old style VAX just made it more interesting.  :-)

  13. Joseph Koss says:


    Most of the Structured Basics that I have seen for the past two decades or so have allowed ARBITRARY bases..

    Dim foo(13 To 37)

    ..or even..

    x = 778

    y = 779

    Dim bar(x To y)

    This is much worse than having a base of 1. A function could be passed an array of literally any base (and any number of dimensions too.. another issue)

    VB.NET enforces a 0 base, and dimensionality is explicit.. but VB6/VBA is still much more popular in the business world (I would go out on a limb and say that globally, more lines of VBA code have been written than any other language.. due to the complete dominance of MS Office)

  14. CarlD says:

    @AsmGuru62 There's more (and less) to it than simply memory being scarce:  On the machines typical of the age when Fortran was created, addresses were smaller than values, so storing the constant once and passing it by address actually saved memory.  For example, on one series of CDC machines that I worked on, an Integer occupied 60 (or 64) bits of memory, while an address was only 18 bits.

    Today it's frequently the other way around – addresses are larger than the stored value, so passing by address actually uses more memory instead of less.

  15. David Walker says:

    Humans have counted lists of things starting at 1 for hundreds of thousands of years (or thereabouts).  Starting arrays at 0 is convenient for array indexing in computer code (fetching from the starting address plus (index times item size)), but it's not the natural place to start counting a list of things.  If I tell you that Mary has 5 apples, and Bill takes two, I wouldn't number Mary's apples from 0 to 4. :-)

  16. David Brooks says:

    This brings back a horrible memory: the fact that the early versions of Primos (the Prime Computer operating systems) were written in Fortran. Shudder…

  17. lefty says:

    So do I understand this right?

    The __fortran calling convention is really the __stdcall calling convention, but it's not the calling convention that the FORTRAN compiler (at least the now-defunct Microsoft Fortran PowerStation) uses?

    Do current FORTRAN compilers use the __fortran calling convention?  Or do you have to resort to custom assembly routines to interface FORTRAN and C on Windows?

    These are really rhetorical questions, since I personally deal with these issues by not doing anything with FORTRAN anymore, thankfully.  I don't even know if you're still supposed to write "FORTRAN" in all uppercase. And I can't be bothered with looking it up on Google.

    [The __fortran calling convention establishes a FORTRAN-compatible stack convention, but you have to finish the job yourself by passing the parameters in a FORTRAN-compatible way. __fortran just makes the whole thing possible. -Raymond]
  18. Poochner says:

    @CarlD (shudder), the days of 6-bit bytes, or variable-length characters if you want both upper and lower case, and colons being strong magic.

    Fortran's not quite dead, just long in the tooth. For example, the GCC project includes a Fortran-95 compiler.  The web page says it includes legacy Fortran-77 support, even though the g77 binary has been dropped.

  19. James Curran says:

    @Joseph K:

    The point I was make is that if you jsut say

    DIM X(10)

    It's the same as

    DIM X(0 TO 10)

    while many vb programmers believe it is

    DIM X(1 TO 10)

  20. Trillian says:

    class Mystery


       static void Main()



           Console.WriteLine("According to the computer, '3' concatenated with '1' is " + Concat("3", "1"));


       static string Concat(string i, string j)


           return i + j;


       //  What does this method actually do?

       static unsafe void Magic(string i)


           fixed (char* ptr = i) ptr[0] = '9';



  21. Joseph Koss says:

    I think I could tolerate everything but arrays being 1-based. I suppose its better than leveraging support of an arbitrary base (BASIC, etc..) but not by much, since most often the usage of an arbitrary base *IS* 1.

  22. Cheong says:

    @Joseph Koss: I've seen people writing VB code using "For i = LBound(arrX) to UBound(arrX)" pattern. I guess I know the reason now…

  23. Daev says:

    Today's post is either an eerie coincidence, Raymond, or you read the ancient Usenet newsgroup alt.folklore.computers like I do.

    A couple of days ago, someone started this a.f.c thread asking about the "fortran" keyword in K&R C:…/9b11f1503f888f53

    …and notice who the first reply is from.  (That's the sort of reason I keep reading that newsgroup.)  Then someone brings up the __fortran keyword in MSC, which actually matches the use of the "fortran" keyword on VMS: "use the OS calling convention instead of the C one."

  24. Brooks Moses says:

    As a slightly-curmudgeonly Fortran programmer (and unabashed Fortran apologist), I want to point out that this particular bug is almost more of an urban legend at this point than a bug — I don't think it affects any Fortran compilers written since, say, Windows 1.0 entered development, and probably not many since 1970.  I certainly have never managed to get it to "happen" on any of the compilers I've used.  Aside from a painful lack of error-checking that's long-since been rectified, it requires a confluence of a number of implementation choices like constant pools that are no longer common, and certainly are not required by the Fortran language.

    (A digression there, since Timbo found the effects of using a constant pool odd — this isn't a Fortran thing, but a general implementation detail that could affect any language.  It came about on machines that didn't have an easy way to express in machine code "load this literal number into memory".  To do that, you'd have to construct the value with several instructions — load this 8-bit literal, shift it 8 bits, load another 8-bit literal, add them, repeat until all 32 bits are loaded, or somesuch like that.  And so the compiler would instead find all the literal numbers used in the code, set up a memory pool to contain them, and initialize them all once at the beginning of the program.  Also, if your address space is smaller than your constant values, it saves code space to do it that way.)

    I'd also note the technicality that "Fortran passes everything by reference" is also a not-entirely-accurate generalization; what Fortran (as a standardized language) does is allow a function to modify any of its arguments, and its up to the particular Fortran implementation how exactly that works.  You can do that with pass-by-reference, but you can also do it with pass-by-value-and-return, or other methods.  And, since Fortran 90, the programmer can also annotate arguments as "intent(in)" to indicate that they aren't going to modify them, and the compiler can consider that in implementing the calling interface.

    Also, to answer Lefty's question about linking Fortran and C, the more recent Fortran standards have official ways to link C functions, which addresses part of this.  Otherwise, it depends on the compiler, but for most compilers it's reasonably straightforward if tedious.  Finally, starting with Fortran 90, the official capitalization is "Fortran".

  25. Random832 says:

    "The last two Fortran Standards have a requirement that Fortran allow calls directly to C" In what way does that remove the need for this? You didn't mention if there is a requirement for Fortran to allow being called from C.

  26. Burak KALAYCI says:

    It is my understanding that an index starts at 1, an offset starts at 0. If something that looks like an index starts at 0, then there is something wrong, however convenient it may seem.

  27. Paul says:

    "Since Magic modified the constant One, any further use of the constant 1 ends up using the value 9!"

    TRWTF is stuff like that.

    I've heard of people doing "if (1 == i) { … }" in order to get the warning when/if they do "if (1 = i) { … }". Get it the other way round, and i becomes 1. Like this, 1 cannot become i and there is much wailing and gnashing of teeth. Except with fortran.

  28. katchu says:

    Almost nothing in the calling convention discussed here is Standard Fortran.  (Including the spelling which changed to Fortran about 1977, 33 years ago). I understand we are talking about MS Powerstation Fortran which had many excellent attributes not the least of which was that it was nowhere near any Fortran standard in its implementation. The calling convention under discussion is a terminology invented by some C programmers to allow C and Fortran program procedures to call one another. It has nothing to do with the Fortran Language _per se_ (It never was part of the Fortran standard but was an implementation-dependent convention made of necessity if not desperation).  The last two Fortran Standards have a requirement that Fortran allow calls directly to C, so these non-standard "standard" calling conventions (ouch) are actually quite foreign to Fortran nowadays.

    For the last 20 years (since Fortran 90) a *conforming* program can't modify constants. Indeed the intent to modify (or not) any dummy arguments (variable or not) must be expressed explicitly with interface blocks or implicitly using modules with argument definition flourishes. Also, the implementation details of how a subroutine vs. function works is processor-dependent. And whether variables are passed by reference or value is processor-dependent. Processor-dependent means it is up to the C programmers who write the Fortran compiler and is nowhere defined in the Fortran Standard.

    "Ye Olde FORTRAN" had arrays that began with 1 and that is still the default, however this is certainly not true now, and not for 20 years. (To be fair C today is NOT K&R  C either).

    "Ye Olde FORTRAN" was not "Highly Evolved", however anyone with eyes to read the 1990, 1995, 2003 and 2008 Fortran Standards will perceive significant evolution.

    Zames "Print" statement conforms to no Fortran Standard I've ever seen and he shows something that 1) he did not understand or recall correctly, or 2) was not a Fortran Print statement but a user-defined function or ungodly compiler extension, or 3) worse. The Fortran Format statement that he might be referencing is a language unto itself (shudder).

    The Gnu Compiler Collection does include a Fortran compiler, named gfortran. (Do not confuse this with g95 which is a different compiler). gfortran differs greatly from 1977 Fortran. It implements the Fortran 95 Standard, most of the Fortran 2003 Standard and (I believe) might implement some Fortran 2008 functionality.  It can compile proper Fortran 77 programs for compatibility purposes, given that there are several million lines of quite efficient old Fortran code around.

    FORTRAN 66 is indeed "long in the tooth" but then so is Kernighan and Ritchie C. I don't suppose anyone would compare K&R C to the latest C# language definition, so let's not do the same with FORTRAN 66 to any other current language (OR to modern Fortran).

    Fortran continues to exist because it is an evolving language, adapting to the needs of its user base.  To be sure other languages have been created to more promptly deal with inadequacies in existing languages (including Fortran, C, C++, Java, whatever).  There must be something positive to be said of Fortraners who persist using the same language name while completely changing the language itself.  Myself, I gave up at Fortran 95.

  29. James Curran says:

    @katchu: The function I described was definitely user-defined.  I only described some 1xx and 9xx codes, but there were also 2xx, 3xx, 4xx etc codes which formatted our internal use data structures in particular ways.

    SO, it was the standard method of output used by applications in that company (this was circa 1985, and they tended to be a bit behind the technology curve, so it may not have been even a full Fortran77 compiler).

  30. Ivan K says:

    Fortran 77 for Engineers and Scientists. First book about a language I ever used at Uni… 18 years ago amidst talk of Fortran 90-something. Gotta love a language that advertises its age, like personalised license plates. That's awesome Trillian. Even if one has to explicitly allow unsafe in the project settings the fact you can do Concat("3", "1")…

    VS2010: According to the computer, '3' concatenated with '1' is 91.

  31. AsmGuru62 says:

    off-topic, probably…

    I wonder how are these 1-based indexes are implemented? Like, when array access happens by index, stored in another variable: A(I) – does it mean that decrement of index value happens just before memory access? Or, ALL Fortran arrays have a 'spare' element at the beginning of each array dimension, so index may be not incremented, but used as is? First approach will slow down the code, second will increase memory footprint.

  32. Burak KALAYCI says:

    @AsmGuru62 I think implementation details are not that important. Maybe array address is stored so that it points to -1st offset (as if there were a 0th element but in fact there isn't) and so there's no leaking disadvantage.

    1-based index values are the natural ones. If a language implements this, it is a nice feature – nothing else.

    High level languages do have disadvantages because of trade-offs. This is expected. A feature like 1-based index values IMHO brings a language way higher (closer to humans) than crap like garbage collection.

  33. RonBass says:

    As someone who started writing FORTRAN (FORTRAN II and IV) code in the mid 60's, this post is seriously amusing.  Back in the day, there was no stack, which had at least three important consequences.

    The first was that all local variables in a function/subroutine were "static", in that they remembered their values from call to call.  It was quite common for a routine to have two entries, the first of which would be called to set up the local variable values that would then be used in calls to the second entry.  A lot of engineering and physics code that was still in use in the late 80's still used this "feature".

    The second was the way that arguments and the return address were passed to a routine.  With no stack, the return address had to be stored in the called routine.  On the IBM mainframes of the 60's, the machine code used for a call to a routine stored the return address in the first word of the routine and returned by jumping to this address (with a suitable offset).  The offset took account of the fact that the addresses of the arguments were stored immediately after the call to the routine.

    The third was that recursion was strictly illegal.  Since a second call to a routine would cause the return address to for the first call be overwritten, there was no way to exit the routine. Programmers of the time learned to use iteration instead of recursion.

  34. katchu says:

    @Random832. I don't know about anything in the Fortran Standard that specifically addresses Fortran being called by C programs. This is my ignorance–as I said I bailed out at Fortran 95 and this facility came in with Fortran 2003. (sigh). I wrote a lot of Fortran wrappers to Win32 functions using compiler-specific facilities (Thanks, Raymond, you were a great help with that). I seldom wrote Fortran code to be called by C programs. (Probably because I'd most likely use C in that case anyway ;^).

  35. katchu says:

    @ZamesCurran. Yeah, I worked with some old Fortran like that. I often wrote my own I/O routines in an attempt to simplify formatting within some project's specifications. The challenge was to make it *simpler* and *less* error prone than what I'd do with the native Fortran I/O methods. I commiserate with you on that horrid convention you were forced to use. I put myself in that box a few times.

  36. Kallee says:

    fortran calling convention is indistinguishable from pascal

Comments are closed.