Example: passing data between FORTRAN and C

I was recently trying to pass data back from C to FORTRAN for a program I'm using. While I found plenty of stuff on sending data from FORTRAN to C, but when I tried to use it in reverse, I got some gibberish. Below is my solution and here is a gunzip'd tarball of all the files involved.

mapsetup.c: the meat of this little entry

/* mapsetup.c -- Miles V. Aronnax
 *   Functions to read, store and return values from the mapping table.
 */

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

// Structure for storing the parsed mapping table.
struct nucleus_mapping_table {
	char nucleus_name[32];
	float ground_state_energy;
	char storage_location[200];
} numap[3];

// Get nucleus name
void mapget_name(int *nucounter, char *name) {
	int idx = *nucounter - 1;
	strcpy(name, numap[idx].nucleus_name);
}

// Get absolute ground state energy
void mapget_eabs(int *nucounter, float *eabs) {
	int idx = *nucounter - 1;
	*eabs = numap[idx].ground_state_energy;
}

// Get nucleus storage folder
void mapget_nloc(int *nucounter, char *nloc) {
	int idx = *nucounter - 1;
	strcpy(nloc, numap[idx].storage_location);
}

// Read values from a table row (line) and load into numap.
void parse_table_row(int idx, char *line) {
	char *afield;
	afield = strtok(line, "\t"); // first column: number
	strcpy( numap[idx].nucleus_name, strtok(NULL, "\t") );
	numap[idx].ground_state_energy = atof(strtok(NULL, "\t"));
	strcpy( numap[idx].storage_location, strtok(NULL, "\n") );
	printf("   Stored: {%s, %f, %s} --> numap[%i]\n",
		numap[idx].nucleus_name,
		numap[idx].ground_state_energy,
		numap[idx].storage_location,
		idx);
}

// Read values from mapping table fspec into array numap.
void read_mapping_table(char *fspec) {
	printf("  In read_mapping_table()...\n");
	int idx=0;
	char line[100];
	FILE *mapfile;

	// Open the mapping file.
	printf("  fopen(%s, r)\n", fspec);
	mapfile = fopen(fspec, "r");
	if( mapfile==NULL ) { printf("Couldn't open mapfile.\n"); exit(0);}

	// Read the file one line at a time.
	while(!feof(mapfile)) {
		fgets(line, 100, mapfile);
		//printf("line=[%s]", line);
		if( line != "" && strlen(line) > 5 ) {
			printf("  Parsing table row %i...\n", idx);
			parse_table_row(idx, line);
			idx++;
		}
	}

	// Close file and exit subroutine.
	fclose(mapfile);
}

test.f: how to call the C functions from FORTRAN

! Fortran test: calling c functions from mapsetup.c
!   Miles V. Aronnax
program test_this
  integer idx
  real ground_state_energy
  character*32 nucleus_name
  character*200 storage_location

  write(*,*) "Begin program test_this..."

  ! Read nuclei.map file into c array struct numap.
  ! Note addition of null character to string. C expects strings
  ! to be null terminated...fortran doesn't do that automatically.
  call read_mapping_table("nuclei.map"//CHAR(0))
  write(*,*) "Call read_mapping_table done."

  ! Clear the fortran varables before trying to get values from c functions.
  ! This prevents strings from containing random data if the string length
  ! is less than the variable size.
  ground_state_energy = 0
  nucleus_name = ""
  storage_location = ""

  write(*,*) "Reading values in fortran using c functions..."

  ! There are 3 rows of the numap table.
  ! I was just lazy here. I could have made the numap table
  ! dynamically allocated and then had a function to return
  ! the number of entries, but I didn't so...*shrug*
  idx = 1
  do while (idx < 4)
    call mapget_name(idx, nucleus_name)
    call mapget_eabs(idx, ground_state_energy)
    call mapget_nloc(idx, storage_location)
    write(*,*) "  Nucleus ", idx, " = {", &
		&trim(nucleus_name), ", ", &
		&ground_state_energy, ", ", &
		&trim(storage_location), "}"
    idx = idx + 1
  enddo

  write(*,*) "End program test_this."
end program test_this

Makefile: instructions to compile

# Mapping Table Test Makefile -- Miles V. Aronnax
#   Need CC=a c compiler, FC=a fortran 90+ compiler
CC=gcc
FC=gfortran42

default: mapsetup.o test.f
	${FC} -ffree-form -fno-underscoring -o test test.f mapsetup.o

# nm mapsetup.o is informational. It dumps the list of symbols in the .o file.
mapsetup.o: mapsetup.c
	${CC} -c mapsetup.c
	nm mapsetup.o

clean: 
	rm -f *.o *.mod *.core test

nuclei.map: the input file

1	47Ca	-406.05400	/path/to/47Ca
2	48Ca	-415.99000	/path/to/48Ca
3	49Ca	-421.13687	/path/to/49Ca
AttachmentSize
maptable.tar_.gz1.86 KB