Operating System - HP-UX
1837893 Members
3020 Online
110122 Solutions
New Discussion

Re: assigning a long long to a long

 
Satya_6
Frequent Advisor

assigning a long long to a long

Hi,

I have a code that reads a data from a binary file which can be 8 byte long or 4 byte long (based on where it was saved, if it was saved on a 64bit host, it will have 8 byte long data, other wise 4 byte). So I use the following code

readBigValue(long long *bval)
{
long long lval = 0;

size_t = m_pHeader->size_to_read;
fread(&lval, size, 1, m_pFile);

if(m_bSwap)
Swap(lval);

long val = (long)lval;
*bval = lval;
#ifdef _DEBUG
fprintf(stderr, "read val: %d\n", val);
#endif
}

The output I get is 0. If I use an array of 2 long and manage with either varr[0] or varr[1]
(based on the endianness) it is fine

Can you please advise me how to handle a situation like this

TIA
Satya
7 REPLIES 7
A. Clay Stephenson
Acclaimed Contributor

Re: assigning a long long to a long

There is something wrong with this line:

size_t = m_pHeader->size_to_read;

I suspect that you meant
size_t size = ...

There are several things wrong:
1) You are trying to transfer binary data from 1 platoform to another; in addition to size and endianess, there is another aspect you are not considering and that is data alignment. I suspect that is why arrays work but plain longs do not.

In any event you are going about this is in a more or less Mickey Mouse way. What you should be doing is writing and reading the data in XDR (external data representation) format. The XDR library routines take care of byte-swappping, size, alignment, and endianess automatically because the #defines are instantiated when the machine-specific library code is compiled. All you have to do is use the functions and XDR takes carew of the rest. The good news is that if you port to another platform or OS, nothingh will have to change.

Man xdr, xdr_simple for details.
If it ain't broke, I can fix that.
Tom Henning
Trusted Contributor

Re: assigning a long long to a long

Clay:

Although I have to aggree with you in theory, XDR on both ends would be a better method, in the Real World sometimes you cannot control both ends of the data flow. I routinely get handed a new input file specification (from a COTS program) and get told they we are going to be getting files in this format next week and the users need the data the next day (or the same day). So a new filter has to be generated to convert the file format into what we use internally.

Satya:

I see a couple of things wrong with your code. To start with though, you should post a complete, compilable, expample of the problem, cut-and-pasted into the posting not re-typed. This is so that the folks you are asking for help can test the code themselves if they are so imclinded to do so. The most glaring problem with the above I can see is:

if(m_bSwap)
Swap(lval);

This does not return/alter anything in the calling function. The value of lval is copied and, I assume from the function's name, byte swapped in the Swap function. But C *always* uses call by value, so a **copy** of lval is byte swapped and nothing is altered in the readBigValue function. You either need to pass the address of lval to Swap, or return the swapped value back from Swap.

Example (return value):

if (m_bSwap)
lval = Swap(lval);

or, for the address version:

if (m_bSwap)
Swap(&lval);

Either way the definition of the Swap function will have to be changed and probably some of the code within. Of the two, I would probably go with the return a long long version, but it's doable either way.
What is it that possesses otherwise sane individuals to change something just because it has not been changed in a while?
Satya_6
Frequent Advisor

Re: assigning a long long to a long

Hi,

thanks for the information.

main(int argc, char **argv)
{
long val = 200;
long long big_val = 0;
long pval;
FILE *fp = NULL;

fp = fopen("test1", "wb");
fwrite(&val, sizeof(long), 1, fp);
fclose(fp);

fp = fopen("test1", "rb");
fread(&big_val, sizeof(long), 1, fp);
/*
pp = (unsigned int *)&big_val;

pval = (pp[0]) ? pp[0] : pp[1];
*/
pval = big_val;
fclose(fp);

fprintf(stderr, "read value: %d\n", pval);
}

If I run the above program on linux, the output is 200, whereas it prints 0 on HP-UX, SUN and IBM.

I have to use the code in the comment to get proper assignment. Can you please suggest why is this beahviour?

TIA
Satya
Tom Henning
Trusted Contributor

Re: assigning a long long to a long

Satya:

Okay, I think I can understand what's going on, but since I am NOT a C expert some of this is guesswork, but educated guesswork.

First: in the code you posted you write out 4 bytes (a long) to the file. This is fine, but then you go back and read that 4 bytes back into a long long, 8 bytes in length. This read then places that 4 bytes into the *high order half* of the long long big_val variable.

Since the big_val variable now holds some large number, which will not fit into a normal int, the pval=big_val line simply copies the *low order half* of big_val into pval.

The reason the commented out code works is that you are accessing the 8 byte long long as if it were two seperate 4 byte long values, and your line: pval = (pp[0]) ? pp[0] : pp[1]; will grab whichever half of the long long that is non-zero, you get the correct result.

Clear as mud? I have attached a modification of your code to this post that might help explain things a bit. I am not a C expert, and I was in a bit of a hurry, so this is not my best code.
What is it that possesses otherwise sane individuals to change something just because it has not been changed in a while?
A. Clay Stephenson
Acclaimed Contributor

Re: assigning a long long to a long

In any event, you code is flawed -- even when it works because it will only work when the value fits into a 4-byte integer. You are assumming that half of the 8-byte value is always zero.

I return to my "correct" solution - XDR.
If it ain't broke, I can fix that.
Tom Henning
Trusted Contributor

Re: assigning a long long to a long

Clay:

I aggree with you completely on the best solution. And my code, as you point out, is still flawed which I aggree with completely. There are times, though, when you cannot change the other end of the process to write XDR files, so I was attempting to point out a possible solution approach. That was the assumption I was proceeding on.

The problem is, and will continue to be, is that satya is attempting to read four bytes into an 8 byte variable. This will be read differently on a Big-endian and small-endian platforms. Always. XDR, or even just plain ASCII, is the best solution for this, but I was also trying to answer the question of "why does this not work".

Zero points for this one please.
What is it that possesses otherwise sane individuals to change something just because it has not been changed in a while?
Satya_6
Frequent Advisor

Re: assigning a long long to a long

Thanks for the info guys. I guess I would change my code to use the XDR. (of course, I have already written funtions like read_int, write_int, read_long, write_long.... the hard way I guess)

I had to read the 4byte data into 8byte data type, because the input file might have come from a 64bit host. So I have done that "using the non-zero half" of the read 8byte data (only when I know that the data I am reading is just 4byte long).

Thanks again for the suggestion

Satya