|
What if I want to change the Fortran Library function code?
If I have to change it in the Fortran Library source and rebuild in the old setup, then I require to change all my Fortran Source to be converted to C++.
Please consider my above requirement too. How to do modifications and build library files from the Fortran library source without using Fortran compiler in VS97 setup?
|
|
|
|
|
manoharbalu wrote: What if I want to change the Fortran Library function code? Then do that.
manoharbalu wrote: If I have to change it in the Fortran Library source and rebuild in the old setup, then I require to change all my Fortran Source to be converted to C++. Why? As long as the function return type or the parameters are the same there is even no need to touch the C/C++ code (provided that you can import the library created by the old compiler as suggested by me).
manoharbalu wrote: How to do modifications and build library files from the Fortran library source without using Fortran compiler in VS97 setup? That makes no sense. To compile Fortran code you need a Fortran compiler.
If you want a more recent Fortran compiler without paying for it you can use GNU Fortran[^] which can be also used with Windows.
If you don't want to use any Fortran compiler, you have to rewrite the code in C/C++.
[EDIT]
There is no "easy" way. Even when using some kind of automatic conversion you have to do some manual work and check if the results are identical to the original version. This often requires understanding what the functions are doing. Then it is better to do the conversion manually too.
[/EDIT]
|
|
|
|
|
I am going to interrupt here because Jochen may be misleading you, while not meaning to.
While he has shown a simple function with a double in out etc that is all nice and easy like he has indicated because they are all standards in both languages.
The thing that gets a bit fun is if your interface exchanges has string, multi dimensional arrays and variant records and the like which he hasn't mentioned. So do you have any pascal specific structures being exchanged, stuff your Pascal compiler would have known but C++ doesn't have. For example your pascal string the first byte is the length and then the string data follows with no ending #0 character so C++ will crash and die if you interface that as a C string, you have to marshal it. Any multi dimensional array will similarly be backwards row major in C++, column Major in Pascal/Fortran. Complex numbers are another thing that doesn't exist in C++ so if you have them on the interface they need special handling. If you have Pascal/Fortran variant records you will need structures with unions and packing control with C++ and a lot of marshalling. Probably look at the library interfaces and write out all the different types exchanged on the interface as a start.
So it's exactly like how you link it to Delphi but sometimes C++ will have no idea of the type you are exchanging, unlike Delphi which natively knows them as the languages share the type definitions.
There is also an added complication we need to talk about, your library files will be strictly ANSI and strictly 32 bit to link. If you select 64 bit complilation and unicode or wide character set on the C++ compiler you will not be able to link the old libraries, they would require what is referred to as a thunk interface which would have to be then written.
In vino veritas
modified 9-Jun-16 10:56am.
|
|
|
|
|
Since your existing libraries can be linked, you need not convert them all at once. However, if you really do intend to abandon the Fortran compiler, then convert them you must, eventually. However, C++ and Fortran are enough alike that the conversion may be simpler than you think. For instance, the control structures should be fairly straightforward. While you may have to visit each one briefly, I suspect that a lot of the conversion can be handled by editor macros or Perl scripts written around regular expressions.
If the libraries use PRINT and FORMAT statements, all of which will need to be completely rewritten to use something like sprintf() , you may not be able to do quite as much with automation, though I would explore it. It's been too long, and I've forgotten most of what I once knew about FORMAT statements, but it's quite possible that you can accomplish much of that conversion with regular expressions, too. Along that line, since they are essentially literal constants, consider replacing the FORMAT statements with #define macros or string resources, so that they incur little or no runtime overhead. There is a trade-off between #define macros and string resources.
A #define resolves to a constant that is baked into the code, and costs basically nothing to use.
A string resource requires a Windows API call (LoadString ) every time you need a new pointer to the string. If you set your character set to Unicode and null terminate your string resources, LoadString can return a pointer to the string, right where it sits. There is a resource compiler option, settable in the project configuration, to null terminate your resource strings. Otherwise, you need a buffer of up to 4097 TCHARs to hold each string. Better yet, let MFC look after all of that by using its CString class, which even sports a LoadString method that looks after the memory for you.
Another potentially thorny issue is COMMON blocks, either blank or labeled. Blank common is essentially process global storage that must be externally linked, and is usually easiest to define as part of the source file in which main() is defined. If there are also labeled COMMON blocks, consider putting each into a static class. Regardless, the actual common block definitions should go into header files. If you surround them with preprocessor guard code, you can define the common blocks and the routines that use them in the same header. Using the guard code lets you get away with defining the same common block in two or more headers, even if the same program includes all of them.
|
|
|
|
|
|
To be able to advise you I need to know a couple of things
1.) Are we talking Fortran 77 or Fortran 90 code in the libraries and what complexity on exchange interface.
2.) How closely are you trying to mimic the functionality of the Delphi Application.
For point 1 there are some real complexities in linking Fortran 90 libraries to C++ as most of the advanced features are more closely related to Pascal than C++. Things that will give you nightmares are things like multi dimension arrays in column-major order, variant data fields require special conversions and any strings exchanges. So conceptually the linking of the libraries is easy but if the exchanges out of the Fortran libraries are complex the problem turns to a nightmare. So it's pretty much the same as linking them to Pascal but there are less consistency with datatypes used in the languages.
With point 2, I would first question why you want to use MFC and C++ for that matter? Delphi is much more structurally similar to C# this will give you the idea
Delphi vs. C# comparison | vsChart.com[^].
C++ is a level lower than Delphi, so what I am wondering here what is driving the want to bring the development onto C++. Don't get me wrong if you have a good C++ programmer they can easily convert it but the exact mimic of the framework well that is another story. I wrote the complete clean room copy of the Borlands objects unit that is in FreePascal (you will find me on the credits). I have also actually written a mimic of the whole Delphi 3 framework in C++ for an application I needed to exactly mirror and it took me just under 2 years. So is this being driven by a programmer wanting to make this choice or is it just a thought bubble.
I have similar reservations about MFC. It's still "current" and "used" but even Microsoft has now released it as free to use in VS2015 as it's commercial value is receding. Commercially most would select a different framework and to do that you start asking yourself do you need cloud access and the new technologies. If you don't need these you might select MFC but there are other choices.
In vino veritas
|
|
|
|
|
|
Your first link is bad.
I would not use system() to spawn a console app. Use ShellExecute() or CreateProcess() instead where you have (some) control over the ensuing window.
As far as WinMain() goes, see here.
"One man's wage rise is another man's price increase." - Harold Wilson
"Fireproof doesn't mean the fire will never come. It means when the fire comes that you will be able to withstand it." - Michael Simmons
"You can easily judge the character of a man by how he treats those who can do nothing for him." - James D. Miles
modified 9-Jun-16 9:12am.
|
|
|
|
|
It is impossible to guess what that code is supposed to be doing, or why it starts with a message box about a memory access error.
Please edit your question and explain exactly what you are trying to achieve. If this is just code from the internet that you do not understand then it would be better to contact the author.
|
|
|
|
|
Sometimes I just shake my head at answers offered ... anyhow moving on
Basically your definition of WinMain isn't correct it has parameters and a call directive, it will look like an overloaded function in that form
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow){
I haven't done this in ages but you had a console app and are trying to turn it to a windows app so there will be a project setting somewhere. To be honest the fastest way to do this will be to set the project up from scratch. Delete all the files in your directory except the source files and stuff you made. Then goto "new project" and select your directory but make sure you select Win32 Application not Win32 Console Application. On the next screen click on the "application settings" and tick the box "empty project". Ok all that and you get an empty project.
Now on the source files entry in solution explorer simply select "add existing item" and bring your source files in as you need.
With the right WinMain you are then good to compile and all should be fixed.
If that all gets too hard here is one I prepared earlier Skeleton Windows App project setup[^]
In vino veritas
modified 9-Jun-16 4:21am.
|
|
|
|
|
leon de boer wrote: Sometimes I just shake my head at answers offered I get much the same feeling with more and more of the questions posted here.
|
|
|
|
|
1.dev enviroment:VC++ 6.0
2.build program in 'release'
3.store 1000000 simple objects in CArray
4.run the program without debug
After running the code , it's about 85M memory cannot be release on my computer.
Can anyone explain and solve the problem for me? Thanks.
BTW:Because of the legency project code,my dev IDE is not allowed to update to the latest VisualStudio. So i have to solve the problem in VC 6.0 IDE.
#include "afxtempl.h"
long int g_cCount = 0;
long int g_dCount = 0;
class CMyTest
{
public:
CString m_str;
CMyTest()
{
m_str = "test string";
g_cCount++;
}
~CMyTest()
{
g_dCount++;
}
};
typedef CArray<CMyTest,CMyTest&> CArrayTest;
void Test()
{
g_cCount = 0;
g_dCount = 0;
CArrayTest testArray;
int count = 1000000;
for(int i =0;i < count; i++ )
{
CMyTest testObj;
testObj.m_str = "test string";
testArray.Add(testObj);
}
testArray.RemoveAll();
testArray.FreeExtra();
}
void CTestMemDlg::OnOK()
{
Test();
CString strInfo;
strInfo.Format("Object construction: %d destruction: %d \r\n",g_cCount,g_dCount);
AfxMessageBox("finish\r\n"+strInfo);
}
|
|
|
|
|
It's a long time since I did any MFC programming, but I suspect that the problem is the definition of CArrayTest. Try making this
typedef CArray<CMyTest,CMyTest> CArrayTest;
(no reference). This will cause every element to be copied into the array, but should work.
If you have an important point to make, don't try to be subtle or clever. Use a pile driver. Hit the point once. Then come back and hit it again. Then hit it a third time - a tremendous whack.
--Winston Churchill
|
|
|
|
|
I think you will find that RemoveAll will remove all the elements from the array but will not actually dispose them (i.e. call their destructors). Should be easy enough to test.
|
|
|
|
|
lostangels wrote:
CArrayTest testArray;
int count = 1000000;<br />
for(int i =0;i < count; i++ )
{
CMyTest testObj;
testObj.m_str = "test string";
testArray.Add(testObj);
}
What will happen if you change this code to
CArrayTest testArray;
int count = 1000000;<br />
testArray.SetSize(count, 100);
for(int i = 0; i < count; i++ )
{
CMyTest testObj;
testObj.m_str = "test string";
testArray.SetAt(i, testObj);
}
|
|
|
|
|
I am not convinced there is a leak ... Please explain this statement
After running the code , it's about 85M memory cannot be release on my computer
How exactly do you know it isn't released?
For example looking at the memory use in Task manager means nothing if that is all you are using. So has this statement got some actual tool basis?
If all you are doing is running task manager run the Test for me twice please one after another.
void CTestMemDlg::OnOK()
{
Test();
test();
CString strInfo;
strInfo.Format("Object construction: %d destruction: %d \r\n",g_cCount,g_dCount);
AfxMessageBox("finish\r\n"+strInfo);
}
If the memory use doesn't double to 170M you aren't leaking memory at all you just misunderstand what windows task manager is reporting.
In vino veritas
modified 6-Jun-16 9:34am.
|
|
|
|
|
How to track for char as input while doing addition for integers. If accidentally given char as input how to prevent it from performing addition calculation.
|
|
|
|
|
You can either
1.) Scan each character of the entry before doing anything with it, this is the generic form of a parser.
2.) Try converting it and if you get an error prompt, reloop and ask for entry again.
3.) Look for an error and if found exit program with error notification.
Which depends on what the source of the number is and what your goals with your program are. For example if the source of the number is a file not much use prompting and asking for re-entry ... files can't do anything about it
So the question comes down as, in the program you are writing what do you think it should do? What is the most elegant and most useful?
In vino veritas
modified 5-Jun-16 3:13am.
|
|
|
|
|
Can anyone explain me what is the difference in determination value?
double a = 0.0;
double a = .0;
double a = 0.;
|
|
|
|
|
No difference, they all represent the value 0.00, they are just different ways of writing it in source code. You could easily have found this out by writing a small program and stepping through it with your debugger.
|
|
|
|
|
Does exist any document or standard how correct use it forms?
|
|
|
|
|
|
Sorry, what do you mean by 'correct'? All the examples are correct, in that they declare the value as zero.
|
|
|
|
|
Hi,
I have a Base Class Header File as follows,
class MyClass,typedef void (MyClass::*PFN_DO_SOMETHING)(void* pData);
class MyClass{
PFN_DO_SOMETHING m_pfnDoSomething;
void Act(void* pData);
}
void MyClass::Act(void* pData){
m_pfnDoSomething(pData);
}
Needless to say, 'pfnDoSomething' has been initialised elsewere. I boiled the question down to the essentials, the correct CPP syntax for calling a member function from a pointer to it.
I get a Compiler error stating that 'pfnDoSomething' does not resolve to a function call.
What is the correct syntax for calling this function.
regards
Bram van Kampen
modified 2-Jun-16 4:00am.
|
|
|
|
|
The solution:
class MyClass{
typedef void (*MyClass::PFN_DO_SOMETHING)(void* pData);
PFN_DO_SOMETHING m_pfnDoSomething;
void Act(void* pData);
};
void MyClass::Act(void* pData){
m_pfnDoSomething(pData);
}
Your errors:
- The asterisk in the
typedef is at the wrong place. - Place the
typedef inside the class to avoid the forward declaration which would not work here with the correct typedef . - The function member name is
m_pfnDoSomething (not pfnDoSomething ).
Note also that there is no need to use the class prefix with the typedef . You may also use:
typedef void (*PFN_DO_SOMETHING)(void* pData);
|
|
|
|