I'm trying to call C functions using fortran (need this for a project).
So first was trying to simply call a non parametrized, void function via fortran.
Kindly help me resolve the following errors in the given code.
C Code for matrix multiplication:
#include <stdio.h>
extern "C"
{ void __stdcall mat();
}
void mat()
{
int m, n, p, q, c, d, k, sum = 0;
printf("Enter the number of rows and columns of first matrix\n");
scanf("%d%d", &m, &n);
int first[m][n];
printf("Enter the elements of first matrix\n");
for ( c = 0 ; c < m ; c++ )
for ( d = 0 ; d < n ; d++ )
scanf("%d", &first[c][d]);
printf("Enter the number of rows and columns of second matrix\n");
scanf("%d%d", &p, &q);
int second[p][q];
if ( n != p )
printf("Matrices with entered orders can't be multiplied with each other.\n");
else
{
printf("Enter the elements of second matrix\n");
for ( c = 0 ; c < p ; c++ )
for ( d = 0 ; d < q ; d++ )
scanf("%d", &second[c][d]);
int multiply[m][q];
for ( c = 0 ; c < m ; c++ )
{
for ( d = 0 ; d < q ; d++ )
{
for ( k = 0 ; k < p ; k++ )
{
sum = sum + first[c][k]*second[k][d];
}
multiply[c][d] = sum;
sum = 0;
}
}
printf("Product of entered matrices:-\n");
for ( c = 0 ; c < m ; c++ )
{
for ( d = 0 ; d < q ; d++ )
printf("%d\t", multiply[c][d]);
printf("\n");
}
}
}
int main()
{
mat();
return 0;
}
Also, the code for calling the function mat from fortran that I wrote is :
program mat_mult !This is a main program.
call mat()
stop
end
On executing the C file I get the following error:
matrix_mult.c:5: error: expected identifier or ‘(’ before string constant
On executing the fortran file using the F77 compiler, I get the following error:
/tmp/ccQAveKc.o: In function MAIN__':
matrix_mult.f:(.text+0x19): undefined reference tomat_'
collect2: ld returned 1 exit status
Kindly help me in identifying the error/correct code.
Thank you.
A few things first
1) I'm assuming you're using a C99 compiler because the C code you've written will not work on a C89 compiler.
2) extern "C" is for C++ programs: not C programs.
Not really sure which compiler you're using. Just assuming you're using gcc and gfortran since it looks like you're on a Linux based system.
gcc just adds a leading _ to the symbols: so mat becomes _mat.
gfortran adds both a leading and trailing _ to the symbols: so mat becomes _mat _.
To make C and Fortran talk
a) Remove the main function from the C code
b) Remove extern "C" declaration. This is a C++ declaration that tells the compiler that the routine mat should not have any name mangling.
c) Since you don't have any parameters, just assume _cdecl and change void mat() to void mat(). If you have to use stdcall, then you need to compile with --enable-stdcall-fixup. stdcall will be needed if the Fortran program has to pass parameters to the C program but that is a different ball game. Instead of _mat _, the compiler generates mat#0
d) Your C routine will now look like
#include <stdio.h>
void mat_()
{
...
}
/* No main */
e) Since the routine mat is not declared in the Fortran code, the compiler needs to know that it is external.
program mat_mult
external mat
call mat()
stop
end
f) Compile and link (say the C program is called mat.c and the fortran program is called matmul.f)
gcc -g -c mat.c
gfortran -g matmul.f mat.o -o matmul
There will probably be a whole load of comments recommending that you use F2003 or F2008 but if you have been told that you have to use F77, then you have to use F77.
Related
Take a look at the following code:
typedef enum {
A, B, C
} Foo;
int foo(Foo x) {
switch(x) {
case A: return 1;
case B: return 2;
case C: return 3;
}
}
GCC 10.2 outputs
<source>:11:1: warning: control reaches end of non-void function [-Wreturn-type]
11 | }
| ^
This is because I can pass something like 42 to foo, not only A, B, or C. So the question is: how to tell GCC that only A, B, or C can be handled by the switch statement, otherwise the behavior is undefined? Compiler-specific functionality is acceptable.
Let me point some solutions that don't satisfy me. First, I could just insert default: __builtin_unreachable(); but this would penetrate case analysis: imagine that apparently I'm adding the D variant and the compiler would not tell me that D is unhandled.
Second, I could insert if (x > C) { __builtin_unreachable(); } before the switch statement, but this is too impossible because switch(x) is actually generated by a macro which doesn't know about the variants of Foo, it knows nothing but some variable x.
Third, I could insert #pragma GCC diagnostic ignored "-Wreturn-type", but again, switch(x) is generated by a macro and this is why I cannot revert the diagnostics to the previous state by #pragma GCC diagnostic pop.
Fourth, I could use an array instead of switch but the returned expressions are not constant and are provided by a user of the macro generating switch(x).
And the last one: I could write return 42; after the switch statement but again I want to disable the warning automatically inside the macro generating switch(x) because it's used extensively in my codebase.
Godbolt
If you feel like engaging in some light masochism, you could crudely implement exception-like behavior using setjmp and longjmp:
#include <stdlib.h>
#include <setjmp.h>
#include <stdio.h>
typedef enum Foo {
A, B, C
} Foo;
#define ENUM_OUT_OF_RANGE -1
jmp_buf env;
int foo( Foo x )
{
switch ( x )
{
case A: return 1;
case B: return 2;
case C: return 3;
default: longjmp( env, ENUM_OUT_OF_RANGE ); // "throw" ENUM_OUT_OF_RANGE
}
}
int main( void )
{
int ex;
if ( (ex = setjmp( env )) == 0 ) // "try" block
{
Foo arr[] = {A, B, C, 42};
for ( size_t i = 0; i < 4; i++ )
{
printf( "value of %d = %d\n", arr[i], foo( arr[i] ) );
}
}
else // "catch" block
{
if ( ex == ENUM_OUT_OF_RANGE )
{
fprintf( stderr, "foo was called with a value outside the range of Foo\n" );
}
}
return 0;
}
Builds with no warnings as follows (at least on my system):
gcc -o exceptions -std=c11 -pedantic -Wall -Werror exceptions.c
Output:
$ ./exceptions
value of 0 = 1
value of 1 = 2
value of 2 = 3
foo was called with a value outside the range of Foo
I'm trying to modify this code (gist as back up) to become gfortran-gcc compatible.
I removed the [VALUE] tags
used POINTER with -fcray-pointer flag for gfortran, instead of the [REFERENCE] tag
removed the __stdcall , because tried the #define __stdcall __attribute__((stdcall)) which caused warning: ‘stdcall’ attribute ignored [-Wattributes]
now this is what I have:
C code CMAIN.C:
#include <stdio.h>
extern int FACT_(int n);
extern void PYTHAGORAS_(float a, float b, float *c);
main()
{
float c;
printf("Factorial of 7 is: %d\n", FACT_(7));
PYTHAGORAS_(30, 40, &c);
printf("Hypotenuse if sides 30, 40 is: %f\n", c);
}
the FORTRAN code FORSUBS.FOR:
INTEGER*4 FUNCTION Fact (n)
INTEGER*4 n
INTEGER*4 i, amt
amt = 1
DO i = 1, n
amt = amt * i
END DO
Fact = amt
END
SUBROUTINE Pythagoras (a, b, cp)
REAL*4 a
REAL*4 b
POINTER (cp, c)
REAL*4 c
c = SQRT (a * a + b * b)
END
the Makefile:
all:
gfortran -c FORSUBS.FOR -fcray-pointer
gcc -c CMAIN.C
gfortran -o result.out FORSUBS.o CMAIN.o
rm -rf *.o
clean :
rm -rf *.out *~ *.bak *.o
However I still get the error:
CMAIN.o: In function `main':
CMAIN.C:(.text+0x1d): undefined reference to `FACT_(int)'
CMAIN.C:(.text+0x4c): undefined reference to `PYTHAGORAS_(float, float, float*)'
I would appreciate if you could help me know:
What is the issue and how can I resolve it?
what is the best method to modify the original code to become gcc-gfortran compatible with minimum change.
P.S.1. also shared on Reddit.
P.S.2. operating system and compiler specifications are same as this question.
Fortran passes variables by reference, as mentioned in the first sentences of any Fortran to C tutorial. So you:
Cannot just remove the [VALUE], you should add the modern VALUE attribute or change the C code to pass pointers.
Should not use pointers on the Fortran side of [REFERENCE], but just remove it.
Use the actual name mangling for your compiler, these days normally subroutine_name_ (appended underscore, name is lowercase) or use the modern bind(C, name="binding_name") attribute.
Without modern Fortran, but with VALUE (it is just a PITA without):
INTEGER*4 FUNCTION Fact (n)
INTEGER*4, VALUE :: n
INTEGER*4 i, amt
amt = 1
DO i = 1, n
amt = amt * i
END DO
Fact = amt
END
SUBROUTINE Pythagoras (a, b, c) bind(C)
REAL*4, VALUE :: a
REAL*4, VALUE :: b
REAL*4 c
c = SQRT (a * a + b * b)
END
and than just change your C names to lowercase (pythagoras_, fact_)... With the VALUE attribute you do not need to introduce all those C temporaries you see in the other answer. The bind(C) is required for VALUE to work properly. It will save you from rewriting the code that calls the Fortran procedures.
For best modern experience use bind(C,name="any_name_you_want") to set the exact linkage symbol name.
In addition to my top comments, Fortran passes by reference, so you have to modify the .c and the .for files.
The code below works. There may be a simpler way to declare things, but this should [at least] get you further along. Caveat: I haven't done much fortran since Fortran IV days, so I'm a bit rusty. I'd defer to Vladimir's VALUE solution as a better way to go.
#include <stdio.h>
#if 0
extern int fact_(int n);
extern void pythagoras_(float a, float b, float *c);
#else
extern int fact_(int *n);
extern void pythagoras_(float *a, float *b, float *c);
#endif
int
main(void)
{
float c;
#if 0
printf("Factorial of 7 is: %d\n", fact_(7));
#else
int n = 7;
printf("Factorial of 7 is: %d\n", fact_(&n));
#endif
#if 0
pythagoras_(30, 40, &c);
#else
float a = 30;
float b = 40;
pythagoras_(&a, &b, &c);
#endif
printf("Hypotenuse if sides 30, 40 is: %f\n", c);
return 0;
}
INTEGER*4 FUNCTION Fact (n)
INTEGER*4 n
INTEGER*4 i, amt
amt = 1
DO i = 1, n
amt = amt * i
END DO
Fact = amt
END
SUBROUTINE Pythagoras (a, b, c)
REAL*4 a
REAL*4 b
REAL*4 c
c = SQRT (a * a + b * b)
END
Here is the program output:
Factorial of 7 is: 5040
Hypotenuse if sides 30, 40 is: 50.000000
UPDATE:
I get the same undefined reference error from your code!
Aha!
One thing I didn't mention [because I didn't think it would make a difference] is that I changed the source file names to use all lowercase letters (e.g. CMAIN.C --> cmain.c and FORSUBS.FOR --> forsubs.for)
With that, the output of nm *.o produces:
cmain.o:
U fact_
0000000000000000 T main
U printf
U pythagoras_
forsubs.o:
0000000000000000 T fact_
0000000000000045 T pythagoras_
The change in the fortran source filename doesn't matter too much. But, the C source filename does!
More to the point it's the filename suffix (i.e. .C changed to .c).
This is because gcc will [try to be smart and] look at the suffix to determine which language the file is written in and compile accordingly. For example, gcc -c foo.cpp will compile the file as if it is written in c++ and not c, just as if the command were: g++ -c foo.cpp
Although .cpp is the [more] usual suffix for a c++ filename, an alternate suffix for c++ files is: .C
That is, most projects use the .cpp convention, but some use the .C convention. One of the reasons for preferring .cpp over .C is that Windows filesystems are case insensitive. So, .C and .c would appear the same. However, POSIX systems (e.g. linux, macOSX, iOS, android, etc.) have case sensitive filenames so either convention can be used.
So, gcc -c CMAIN.C will compile as c++. This does c++ style "name mangling" of symbols--not what we want. In c++, the mangling is done to allow "overloading" of function names. That is, two [or more] different functions can have the same name, as long as they use different arguments. For example:
void calc(int val);
void calc(int val1,int val2);
void calc(double fval);
Here is the output of nm *.o if we use CMAIN.C:
CMAIN.o:
0000000000000000 T main
U printf
U _Z11pythagoras_PfS_S_
U _Z5fact_Pi
FORSUBS.o:
0000000000000000 T fact_
0000000000000045 T pythagoras_
Running that file through c++filt to "demangle" the c++ names we get:
CMAIN.o:
0000000000000000 T main
U printf
U pythagoras_(float*, float*, float*)
U fact_(int*)
FORSUBS.o:
0000000000000000 T fact_
0000000000000045 T pythagoras_
So, try to use lowercase filenames if possible [that is recommended best practice]. But, at a minimum, don't use .C
I wrote a c code: convert integer to string and have a comma every 3 digits, and can anyone give me a hint how to convert it to assembly language???
I just want simply convert it into assembly language! Can't use other library call!
#include <stdio.h>
char *my_itoa(int n, char *buf)
{
int i, j, k=0, l=0;
char tmp[32] = {0};
i = n;
do {
j = i%10;
i = i/10;
sprintf(tmp+k, "%d", j);
k++;
l++;
if (i!=0 && l%3 == 0) {
sprintf(tmp+k, ",");
k++;
l = 0;
}
}while(i);
for (k--,i=0; i<=k; i++) {
buf[i] = tmp[k-i];
}
return buf;}
If your complier is gcc, this answer suggests a nice way to produce a combined C/assembly language file that is easier to read than plain assembly. They use c++, but just replace c++ with gcc:
# create assembler code:
gcc -S -fverbose-asm -g original.c -o assembly.s
# create asm interlaced with source lines:
as -alhnd assembly.s > listing.lst
C compilers conforming to the SUSv2 (Single Unix Specification version 2 published in 1997) can do what you want much more simply by using a locale flag specifier. Here's example C code that works with gcc:
#include <stdio.h>
#include <locale.h>
int main()
{
int num = 12345678;
setlocale(LC_NUMERIC, "en_US");
printf("%'d\n", num);
return 0;
}
This prints 12,345,678. Note, too, that this works correctly with negative numbers while your code does not. Because the code is simply a single library call, it's probably not worth implementing in assembly language, but if you still cared to, you could use this:
In the .rodata section include this string constant:
.fmt:
.string "%'d\n"
The code is extremely simple because all the hard work is done within printf:
; number to be converted is in %esi
movl $.fmt, %edi
movl $0, %eax
call printf
I try to check subnormal numbers. Below is my code. It works, but I do not see a difference between Min positive normal number and subnormal number.
Why ?
/*
isnormal example
ISO C99
http://www.cplusplus.com/reference/cmath/isnormal/
http://www.gnu.org/software/libc/manual/html_node/Floating-Point-Classes.html
http://docs.oracle.com/cd/E19957-01/806-3568/ncg_math.html
compile with:
gcc -std=c99 -lm s.c
run :
./a.out
*/
#include <stdio.h> /* printf */
#include <math.h> /* isnormal, fpclassify */
int TestNumber(double x)
{
int f; // flag
f= isnormal(x);
if (f)
printf ("number %f is normal \r",x);
else printf ("number %.1000f is not normal \n",x);
return f;
}
//----------------------------
int main()
{
double d ;
double MinNormal;
int f;
d = 1.0 ; // normal
f = TestNumber(d);
do
{
d /=2.0;
MinNormal=d;
f = TestNumber(d);
}
while (f);
printf ("number %.1000f is minimal normal \n",MinNormal);
printf ("number %.1000e is not normal \n",d);
printf ("number %.1000e is minimal normal \n",MinNormal);
return 0;
}
Here is my output :
gcc -std=c99 -lm s.c
a#acer:~/cnie/numerical/subnormal/s1$ time ./a.out
number 0.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000111253692925360069154511635866620203210960799023116591527666370844360221740695909792714157950625551028203366986551790550257621708077673005442800619268885941056538899676600116523980507372129181803596078252347125186710418762540332530832907947436024558998429581982425031795438505915243739989044387687497472579022580252545769992829123540932255676896790249605799054288302599621667605717619507439784980479564444580149632075553173315669683173879325651468588102366281589074283217543606141431882102242340570380695573853140084492662205501208072371080928358307527007714254235837645095158066138944836485368656166704349449158753391942346304638698898642932982747054568454770306823378435119933915764534049231 is not normal
number 0.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000111253692925360069154511635866620203210960799023116591527666370844360221740695909792714157950625551028203366986551790550257621708077673005442800619268885941056538899676600116523980507372129181803596078252347125186710418762540332530832907947436024558998429581982425031795438505915243739989044387687497472579022580252545769992829123540932255676896790249605799054288302599621667605717619507439784980479564444580149632075553173315669683173879325651468588102366281589074283217543606141431882102242340570380695573853140084492662205501208072371080928358307527007714254235837645095158066138944836485368656166704349449158753391942346304638698898642932982747054568454770306823378435119933915764534049231 is minimal normal
number 1.1125369292536006915451163586662020321096079902311659152766637084436022174069590979271415795062555102820336698655179055025762170807767300544280061926888594105653889967660011652398050737212918180359607825234712518671041876254033253083290794743602455899842958198242503179543850591524373998904438768749747257902258025254576999282912354093225567689679024960579905428830259962166760571761950743978498047956444458014963207555317331566968317387932565146858810236628158907428321754360614143188210224234057038069557385314008449266220550120807237108092835830752700771425423583764509515806613894483648536865616670434944915875339194234630463869889864293298274705456845477030682337843511993391576453404923086054623126983642578125000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e-308 is not normal
number 1.1125369292536006915451163586662020321096079902311659152766637084436022174069590979271415795062555102820336698655179055025762170807767300544280061926888594105653889967660011652398050737212918180359607825234712518671041876254033253083290794743602455899842958198242503179543850591524373998904438768749747257902258025254576999282912354093225567689679024960579905428830259962166760571761950743978498047956444458014963207555317331566968317387932565146858810236628158907428321754360614143188210224234057038069557385314008449266220550120807237108092835830752700771425423583764509515806613894483648536865616670434944915875339194234630463869889864293298274705456845477030682337843511993391576453404923086054623126983642578125000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e-308 is minimal normal
================edit===============
good program after applaying all the changes from the answers and comments
while (f)
{
MinNormal=d;
d /=2.0;
f = TestNumber(d);
}
and print only 16 digits:
printf ( "number %.16e is normal \n",x);
The way your loop is written, it always ends with d and MinNormal set to the same value. You should move the assignment of MinNormal before the change to d so that it remembers the value of d from the previous iteration.
I am used to Fortran in which I used the namelist sequential read in to get variables out of a file. This allows me to have a file which looks like this
&inputDataList
n = 1000.0 ! This is the first variable
m = 1e3 ! Second
l = -2 ! Last variable
/
where I can name the variable by it's name and assign a value as well as comment afterwards to state what the variable actually is. The loading is done extremely easy by
namelist /inputDataList/ n, m, l
open( 100, file = 'input.txt' )
read( unit = 100, nml = inputDataList )
close( 100 )
Now my question is, is there any similar thing in C? Or would I have to do it manually by chopping the string at the '=' and so on?
Here is a simple example that will let you read Fortran namelists from C. I used the namelist file that you provided in the question, input.txt.
Fortran subroutine nmlread_f.f90 (notice the use of ISO_C_BINDING):
subroutine namelistRead(n,m,l) bind(c,name='namelistRead')
use,intrinsic :: iso_c_binding,only:c_float,c_int
implicit none
real(kind=c_float), intent(inout) :: n
real(kind=c_float), intent(inout) :: m
integer(kind=c_int),intent(inout) :: l
namelist /inputDataList/ n,m,l
open(unit=100,file='input.txt',status='old')
read(unit=100,nml=inputDataList)
close(unit=100)
write(*,*)'Fortran procedure has n,m,l:',n,m,l
endsubroutine namelistRead
C program, nmlread_c.c:
#include <stdio.h>
void namelistRead(float *n, float *m, int *l);
int main()
{
float n;
float m;
int l;
n = 0;
m = 0;
l = 0;
printf("%5.1f %5.1f %3d\n",n,m,l);
namelistRead(&n,&m,&l);
printf("%5.1f %5.1f %3d\n",n,m,l);
}
Also notice that n,m and l need to be declared as pointers in order to pass them by reference to the Fortran routine.
On my system I compile it with Intel suite of compilers (my gcc and gfortran are years old, don't ask):
ifort -c nmlread_f.f90
icc -c nmlread_c.c
icc nmlread_c.o nmlread_f.o /usr/local/intel/composerxe-2011.2.137/compiler/lib/intel64/libifcore.a
Executing a.out produces the expected output:
0.0 0.0 0
Fortran procedure has n,m,l: 1000.000 1000.000 -2
1000.0 1000.0 -2
You can edit the above Fortran procedure to make it more general, e.g. to specify namelist file name and list name from the C program.
I've made a test of above answer under GNU compilers v 4.6.3 and worked perfectly for me. Here's is what I did for the corresponding compilation:
gfortran -c nmlread_f.f90
gcc -c nmlread_c.c
gcc nmlread_c.o nmlread_f.o -lgfortran