I was trying to compile a mixed programming lanaguage (C++/Fortran) sample project provided by Intel Compiler 2013 under Eclipse IDE. I can run this project successfully under Visual Studio IDE (on Windows OS system), but I have not figured out how to run the same project under Eclipse on Linux. The configuration of linking the Fortran to the C++ project in Eclipse IDE is the main issue that troubles me.
Could anyone please tell me how to link these two projects? Thanks. The output should be simple "Testing...123."
Li
The source codes are as follows:
(1) the main program, fmain.f90
PROGRAM fmain
USE, INTRINSIC :: ISO_C_BINDING
IMPLICIT NONE
INTERFACE
SUBROUTINE c_routine (int_arg, str_in, str_out, str_out_len) BIND(C)
IMPORT ! Use declarations from host
INTEGER(C_INT), VALUE,INTENT(IN) :: int_arg
CHARACTER(KIND=C_CHAR), DIMENSION(*), INTENT(IN) :: str_in
CHARACTER(KIND=C_CHAR), DIMENSION(*), INTENT(OUT) :: str_out
INTEGER(C_INT), VALUE, INTENT(IN) :: str_out_len
END SUBROUTINE c_routine
END INTERFACE
CHARACTER(80) OUTPUT_TEXT
INTEGER IN_ARG, OUTPUT_LEN
CHARACTER(80) INPUT_TEXT
INPUT_TEXT = "Testing..."//C_NULL_CHAR
IN_ARG = 123
CALL c_routine (IN_ARG, INPUT_TEXT, OUTPUT_TEXT, LEN(OUTPUT_TEXT))
OUTPUT_LEN = INDEX(OUTPUT_TEXT," ")
IF (OUTPUT_LEN == 0) OUTPUT_LEN = len(OUTPUT_TEXT)
WRITE (*,*) OUTPUT_TEXT(1:OUTPUT_LEN)
END
(2) csub.cpp
#include <stdio.h>
extern "C" void c_routine (
int int_arg, // integer to convert
char* input_text, // text to prepend to converted integer
char* output_text, // output buffer
int output_text_len // length of output buffer
)
{
sprintf_s(output_text,output_text_len,"%s%i ",input_text,int_arg);
}
Related
First of all there is another question with the same title but the solutions offered there didn't work for me. Other question
#include <stdio.h>
#include <stdlib.h>
int main()
{
int a, b, c;
fflush(stdout);//suggested solution in other question
scanf("%d%d%d", &a, &b, &c);
printf("Values entered: %d %d %d\n", a, b, c);
return 0;
}
The code works fine when I run it normally.
Output
1 2 3
Values entered: 1 2 3
But when I run in debug mode nothing is printed. When I hover over the variables they have these values.
a : 56
b : 6422420
c : 6422420
Another solution suggested was to put this code in the start of the main method.
int ch;
while ((ch = getchar()) != '\n' && ch != EOF); //suggested solution #1
Both solutions suggested in the post didn't work for me. I tried them both separately.
EDIT
OS : Windows 10
Compiler : MinGW
I would recommend to use spaces in your scanf format, and to test its return count, so:
a = b = c = 0; // better to clear variables, helpful for debugging at least
int cnt = 0;
if ((cnt=scanf(" %d %d %d", &a, &b, &c)) == 3) {
/// successful input
printf("Values entered: %d %d %d\n", a, b, c);
}
else {
/// failed input
printf("scanf failure cnt=%d error %s\n", cnt, strerror(errno));
}
fflush(NULL); // probably not needed, at least when stdout is a terminal
Read carefully the documentation of scanf (and of every library function) before using it.
BTW, Eclipse is just an IDE or glorified source code editor, your compiler could be GCC or Clang (and you probably can configure your IDE to pass appropriate options to your compiler). And scanf itself is implemented in your C standard library (above your operating system kernel).
But you really need to enable all warnings & debug info in your compiler (so compile with gcc -Wall -Wextra -g if using GCC) and to learn how to use your debugger gdb (breakpoints, step by step, variable querying, backtrace...)
You may want to use fflush and you should compile and run your program in a terminal (not under Eclipse, which is hiding a lot of useful things to you).
I am trying to pass two double arrays from a handler that's written in VBA into the DLL written in C++ and I keep getting an error saying the index it outside the bounds of the array. The arrays contain 800 double values which I need to calculate the correlation between the two arrays using the FFT
function call in the VBA code:
Dim firstDataDbl() As Double = Array.ConvertAll(firstData, Function(d) Double.Parse(d))
Dim secondDataDbl() As Double = Array.ConvertAll(secondData, Function(d) Double.Parse(d))
rdftTest(UBound(firstDataDbl) + 1, firstDataDbl(0), secondDataDbl(0))
definition of the DLL function in VB:
Public Module DLLTest
<DllImport("FFT.dll", CharSet:=CharSet.Ansi, CallingConvention:=CallingConvention.Cdecl)>
Function rdftTest(ByVal length As Integer, ByRef firstDataDblFirstElement As Double, ByRef secondDataDblFirstElement As Double) As Integer
End Function
End Module
Function, written inside the C++ DLL:
void rdftTest(int length, double *input1, double *input2) {
std::ofstream myFile;
myFile.open("C:\\randFolder\\foo.txt", std::ios::out);
myFile << length << " " << &input1 << " " << &input2 << std::endl;
}
Both arrays are always of equal length which is why i'm using only one length argument.
I solved the issue by parsing the UBound(firstDataDbl) + 1 into Integer and then passed that value in the function
I am using a Fortran user subroutine (UMAT) in Abaqus. I use it to run other Abaqus sub-calculations within my main calculation.
The sub-calculation names are variables, so I am defining them this way:
character (len=256) :: strJOB,strOLDJOB
character (len=256) :: strGoToWorkPath,strCommand,strCmdLine
character (len=256) :: temp, strNOEL, strNPT, striCalcs, striCalcsPrev
write(temp, '(i6)') NOEL
read(temp, *) strNOEL
temp = ''
write(temp, '(i6)') NPT
read(temp, *) strNPT
temp = ''
write(temp, '(i6)') iCalcs
read(temp, *) striCalcs
temp = ''
write(temp, '(i6)') (iCalcs-1)
read(temp, *) striCalcsPrev
temp = ''
strJOB = "micro_" // trim(strNOEL) //"_"// trim(strNPT) // "_" // trim(striCalcs)
strOLDJOB = "micro_" // trim(strNOEL) //"_"// trim(strNPT) //"_"// trim(striCalcsPrev)
strGoToWorkPath = "cd C:\AbaqusCalc"
strCommand = "abaqus interactive job=" // trim(strJOB) // " oldjob=" // trim(strOLDJOB)
strCmdLine = trim(strGoToWorkPath) // ' && ' // trim(strCommand)
And then I just use call system(trim(strCmdLine)) to run my sub-calculation.
What is making me mad is that this works for some sub calculations (sometimes just 1, sometimes 100, it's kinda random), but then I get some error of this kind:
Abaqus Error: The following file(s) could not be located: micro_1_1_1#.odb
where # is always a "strange" character (you can see an example here https://www.dropbox.com/s/82b7u7enlxpc62e/1.jpg?dl=0 ). I can confirm (via debug or writing on a file the character variable strCmdLine) that I am executing correctly with the argument "oldjob=micro_1_1_1", like this:
cd C:\AbaqusCalc && abaqus interactive job=micro_1_1_2 oldjob=micro_1_1_1
In some cases Abaqus can find and process the oldjob (file micro_1_1_1.odb), but in another cases he just sticks that strange character between the end of the filename and the ".odb" extension.
My questions would be:
Is this related with the call system() function?
Can this be an error related with Abaqus and not with Fortran?
Is there any other way that I can use to call my Abaqus calculations, instead of call system?
Just something to try, this construct looks perfectly correct
strJOB = "micro_" // trim(strNOEL) //"_"// trim(strNPT) // "_" // trim(striCalcs)
however it can be done I think more neatly using a single internal write:
write(strJOB,'("micro_",i0,"_",i0,"_",i0)')NOEL,NPT,iCalcs
note the i0 nicely takes care of the blanks and strJOB is blank padded out to 256 characters in both cases.
I have a problem with reading a text file in c++ and I can't figure out what is wrong. I need to read few complex numbers from file and do some calculations using matlab functions. So before that I compiled matlab library and included them to my project. I tested them and it works correctly. But when I added a few lines of code for reading data from file I get some errors:
Here is my code:
#include "spectrum.h"
#include <iostream>
#include <fstream>
#include <complex>
using namespace std;
int main(){
mclInitializeApplication(NULL,0);
spectrumInitialize();
cout<<"Initialization success"<<endl;
double input[4] = {10,20,30,40};
mxArray *x_ptr, *x_ptr1;
mxArray *y_ptr=NULL;
mxArray *y_ptr1=NULL;
double *y;
double *y1;
complex<double> com[256];
ifstream myfile("dep.txt");
double a = NULL;
for(int i=0; i<256;i++)
{
myfile >> a;
com[i].real(a);
myfile >> a;
com[i].imag(a);
}
myfile.close();
x_ptr1 = mxCreateDoubleScalar(256);
x_ptr = mxCreateDoubleMatrix(1,256,mxCOMPLEX);
memcpy((void *)mxGetPr(x_ptr), (void *) com,256*sizeof(complex<double>));
mlfSpectrum_slice(1,&y_ptr,x_ptr,x_ptr1);
y = (double*)mxGetPr(y_ptr);
cout<<"Data: "<<input<<endl;
cout<<"Result: "<<*y<<endl;
mxDestroyArray(x_ptr);
mxDestroyArray(y_ptr);
spectrumTerminate();
mclTerminateApplication();
return 0;
}
I tried to use fstream and ifstream too. Anybody knows what I'm doing wrong?
By the way, I'm using Windows 7 32bit, Visual studio 2012 and Matlab R2012b.
You have a linkage problem. The linker can't find the function CrtDbgReport. This is a Microsoft debug function. It is all about writing debug messages using OutputDebugString API. Microsoft lib is kernel32.lib - so have you linked with that? Specifically it is looking for the Unicode version, that's the W on the end: CrtDbgReportW. So you must have set a Unicode build somewhere. ie #define UNICODE.
Is your lib maybe NOT using Unicode.
Another possibility is you are linking against debug matlab lib but you are building a release version of your program. Or vice versa.
I've written a program in F90 which reads in a few input arrays from text files and then combines them through a function to a single output file. One of the input files is named for the day the data was collected using MMDDYY.tuvr and the output file is then named MMDDYY.fxi . I'd like to be able to input the MMDDYY of the data in the command line when running the program instead of having to manually change the code and compile each time, which is why I'm attempting to use getarg, but I cannot seem to make it work properly. The code im attempting to use is listed below (just shows the get arg and the open commands and not the entire program since this is where I'm having trouble):
CHARACTER(len=20) :: arg, tuvrname, fxiname
CALL getarg(1, arg)
IF(LEN_TRIM(arg) == 0) THEN
print*,'No date provided'
STOP
ELSE
tuvrname = TRIM(arg)'.tuvr'
fxiname = TRIM(arg).'fxi'
ENDIF
OPEN(1, file = tuvrname, status='old', action='read')
....
OPEN(4, file = fxiname, status='replace', action='write')
I also tried just using two separate getarg commands and entering MMDDDYY.tuvr MMDDYY.fxi in the command line and the program ran, but it could not seem to find my TUVR file as the output was empty.
I am not really experienced in using getarg. I use get_command_argument from Fortran 2003. I think you just forgot to use // to concatenate the strings.
CHARACTER(len=20) :: arg, tuvrname, fxiname
CALL getarg(1, arg)
IF(LEN_TRIM(arg) == 0) THEN
print*,'No date provided'
STOP
ELSE
tuvrname = TRIM(arg)//'.tuvr'
fxiname = TRIM(arg)//'.fxi'
ENDIF
print *, tuvrname, fxiname
end
or
CHARACTER(len=20) :: arg, tuvrname, fxiname
if (command_argument_count()<1) then
stop "Provide the file name."
end if
CALL get_command_argument(1, value=arg)
tuvrname = TRIM(arg)//'.tuvr'
fxiname = TRIM(arg)//'.fxi'
print *, tuvrname, fxiname
end