问题
I am migrating some legacy Fortran77 code to C/C++. In the Fortran77 code, if 8 characters are read in from a file, they can be stored in a variable of type real*8 without a problem.
Is it possible to do a similar thing in C or C++? If so, how would I do it? I haven't been able to find any solutions on the internet. I need to read in 8 characters using C/C++ and store them in a variable of type double, which is then passed back to Fortran and corresponds to the original real*8 variable.
Many thanks in advance for any help.
EDIT: In response to @sixlettervariables, I'll just clarify my use-case a bit more. The issue I have with his suggestion is that I only know the format of each line (i.e. which fields are strings, which numbers) at runtime, and hence I can't know what members the struct should have statically. The fields also need to occupy a contiguous block of memory in the order they are read in.
Concretely, in one run of the program the format of each line might be: f1:string, f2:number, f3:number, f4:string, but in another f1:string, f2:string, f3:string, f4:number, f5:number. For the first case I'd need:
struct { char[8] f1; double f2; double f3; char[8] f4}
For the second I'd need:
struct { char[8] f1; char[8] f2; char[8] f3; double f4; double f5}
Perhaps there is some way to do this with templates?
回答1:
You do not need to store them in a double
just because Fortran needed to do that. In fact, you absolutely should not do that in your C/C++ code.
Simply store the character data in a character array.
If you're mixing Fortran and C/C++, the two have no idea about one another outside of their ABI. From the C side you can simply claim that the Fortran interface takes a character array, when in fact it is expecting an array of doubles. And the same is true from the Fortran side.
From the C side:
extern void FCHARS(char* str, int length);
/* ... */
int flength = 0; /* optional: length of the string in Fortran terms */
char str[9]; /* in C/C++ add one for \0 at the end */
/* read in up to a block of 8 */
fgets(str, sizeof(str), fp);
/* At this point if you know the 8 characters are space padded to their end
* you have no more work to do, otherwise you may need to fill from the right
* with spaces.
*/
{
size_t ii = sizeof(str) - 1;
while (ii > 0 && str[ii - 1] == '\0') {
str[ii - 1] = ' ';
flength = ii--; /* optional: keep track of our unpadded length */
}
}
/* Once you've space padded the string you can call your Fortran method.
* If your Fortran method accepts a string of unknown length, supply
* `flength`. If your Fortran method expects a string of a fixed length, pass
* the size of `str` (excluding '\0') instead.
*/
FCHARS(str, flength);
As long as you follow the ABI requirements of your Fortran compiler (e.g. CDECL, hidden string lengths passed interleaved) from the C/C++ code, you'll be fine.
回答2:
Sure, just use a cast. You might want to add a static_assert for safety:
double d;
char * b = (char*)&d;
static_assert(sizeof(d) == sizeof(char[8]), "Double must be large enough to hold 8 chars");
回答3:
union Data{
char c[8];
double d;
};
Save the 8 characters into c
, and read it by d
. Example:
#include <stdio.h>
// #include <stdlib.h>
union Data{
char c[8];
double d;
};
int main(){
int i;
union Data data;
for(i = 0; i < 8; i++)
scanf("%hhd", data.c + i);
printf("%e\n", data.d);
// system("pause");
return 0;
}
回答4:
method 1
double a;
char ch;
int i;
for(i=0;i<8;i++)
{
scanf("%c", &ch);
a=a+ch;
if(i!=8)
a<<8; //left shifts by 8 bits, to accomodate another 8 bits on right.
}
method 2
double a
char *ch;
int i;
ch=&a;
for(i=0;i<8;i++)
{
scanf("%c", ch);
ch++;
}
回答5:
Even if it would be possible in C to store several chars and real numbers in a DOUBLE variable because C DOUBLE is equal to REAL*8 because both are double precision float numbers I would strongly advise against it.
This "trick" to store several chars and reals in REAL*8 feels like a hack to save space. I don't think this is needed nowadays and I do not think this "trick" would generate faster code. I would advise to use a UNION as mentioned above.
You could post the FORTAN code which reads the chars and reals into the REAL*8 this would make it easier to help you. And I must say I am intrigued to find out how this is done.
来源:https://stackoverflow.com/questions/16463080/is-it-possible-to-store-8-characters-1-byte-each-in-a-variable-of-type-double