Write int as a 4 byte big-endian to file.

M

MS

Hi,

I need some help with something which is a little over my pay grade. :)

The file which I must write has a header followed by a sequence of ints
each of which must be written as a 4 byte big-endian.

The comp.lang.c has advice on finding out whether your machine is
little-endian or big-endian (little-endian in my case) but not on how to
do the kind of operation I need to do.

I am sorry to say that I simply have no idea whatsoever how to write an
int to a file as a 4 byte big-endian. Can someone show me how please?

Many thanks.
 
D

Don Y

I need some help with something which is a little over my pay grade. :)

The file which I must write has a header followed by a sequence of ints
each of which must be written as a 4 byte big-endian.

The comp.lang.c has advice on finding out whether your machine is
little-endian or big-endian (little-endian in my case) but not on how to
do the kind of operation I need to do.

I am sorry to say that I simply have no idea whatsoever how to write an
int to a file as a 4 byte big-endian. Can someone show me how please?

Break the 4 byte value into 4 *bytes*. Then, write them
INDIVIDUALLY in Big Endian order.
 
M

MS

Break the 4 byte value into 4 *bytes*. Then, write them
INDIVIDUALLY in Big Endian order.

Ahh yes. That is exactly how far I got on my own. Sorry to be a bit
clueless but I don't know how to accomplish that.

I'm also worried about the code being endian specific, the code must
work regardless of whether the machine is little-endian or big-endian,
but I already know how to test which the machine is thanks to the FAQ.

Since it has just occurred to me I should also mention that my int range
is from 0 to potentially the low tens of millions.

Thanks (and sorry for bothering you guys, I have done several web
searches and can't find any page/post that spells it out for me, I was
surprised it isn't in the FAQ - that usually sorts me out).
 
B

Bl0ckeduser

MS said:
Hi,

I need some help with something which is a little over my pay grade. :)

The file which I must write has a header followed by a sequence of ints
each of which must be written as a 4 byte big-endian.

The comp.lang.c has advice on finding out whether your machine is
little-endian or big-endian (little-endian in my case) but not on how to
do the kind of operation I need to do.

I am sorry to say that I simply have no idea whatsoever how to write an
int to a file as a 4 byte big-endian. Can someone show me how please?

Many thanks.

Hi, I'm not a C expert, but the following worked for me on a low-endian
32-bit machine, a low-endian 64-bit machine, and a big-endian 32-bit
machine:

int i = 12345678;
printf("%d\n", (i & 0xFF000000) >> 32);
printf("%d\n", (i & 0x00FF0000) >> 16);
printf("%d\n", (i & 0x0000FF00) >> 8);
printf("%d\n", i & 0x000000FF);

output (identical on all three machines):

0
188
97
78
 
T

Tim Rentsch

MS said:
The file which I must write has a header followed by a sequence of
ints each of which must be written as a 4 byte big-endian.

The comp.lang.c has advice on finding out whether your machine is
little-endian or big-endian (little-endian in my case) but not on how
to do the kind of operation I need to do.

I am sorry to say that I simply have no idea whatsoever how to write
an int to a file as a 4 byte big-endian. Can someone show me how
please?

To write:

void
write_four_bytes_in_MSB_first_order( FILE *file, unsigned long what ){
int i;
unsigned char bytes[4];
for( i = 3; i >= 0; i-- ) bytes = what % 256, what /= 256;
for( i = 0; i <= 3; i++ ) fputc( bytes, file );
}

Although the 'what' parameter is unsigned long, giving an int or
long int argument will work fine provided the signed value fits
in four bytes. The value will be written using a two's complement
representation.



To read:

long int
read_four_bytes_in_MSB_first_order( FILE *file ){
unsigned long bits;
int i;
for( bits = 0, i = 0; i < 4; i++ ) bits = bits*256 + fgetc( file );

return bits < 0x80000000 ? bits : -1 - (long)(bits ^ 0xffffffff);
}

The last part of the return expression guarantees the value can be
read even on machines that don't use two's complement (assuming
the value isn't the most negative two's complement value, which
cannot be represented in the two other representations).
 
S

Sjouke Burry

Hi,

I need some help with something which is a little over my pay grade. :)

The file which I must write has a header followed by a sequence of ints
each of which must be written as a 4 byte big-endian.

The comp.lang.c has advice on finding out whether your machine is
little-endian or big-endian (little-endian in my case) but not on how to
do the kind of operation I need to do.

I am sorry to say that I simply have no idea whatsoever how to write an
int to a file as a 4 byte big-endian. Can someone show me how please?

Many thanks.
Hm... just reverse the routine below....

int little_endian(char *c){
static union{
int k;
char c[4];
}p;
p.c[0]=c[3];
p.c[1]=c[2];
p.c[2]=c[1];
p.c[3]=c[0];
return p.k;
}
 
M

Morris Keesan

Hi,

I need some help with something which is a little over my pay grade. :)

The file which I must write has a header followed by a sequence of ints
each of which must be written as a 4 byte big-endian.

The comp.lang.c has advice on finding out whether your machine is
little-endian or big-endian (little-endian in my case) but not on how to
do the kind of operation I need to do.

I am sorry to say that I simply have no idea whatsoever how to write an
int to a file as a 4 byte big-endian. Can someone show me how please?

We'll assume that this means 4 8-bit bytes.

First, make sure that it will fit:
assert((sizeof(int) * CHAR_BIT) <= 32);
Then put the value into a (unsigned long int), so that you're guaranteed
to be working with an object which is at least 32 bits long, and you don't
have to worry about the implementation-defined results of applying
the >> operator to a signed quantity.
Then simply use bitwise operations (shifting and masking) to pick out
the successive octets of the low-order 32 bits of the int, starting from
the highest-order octet of those 32 bits.

unsigned long int ltemp = intvalue;
for (int i = 0; i < 3; ++i)
fputc((intvalue >> (8 * (3 - i))) & 0xff, file);

Because you're working purely with the numerical value of the number,
this should work regardless of the endianness of the platform you're
doing this on.
 
S

Stephen Sprunk

Ahh yes. That is exactly how far I got on my own. Sorry to be a bit
clueless but I don't know how to accomplish that.

You seem to be hung up on how to extract individual bytes from a wider
type, which is typically done by shifting and masking; this would be the
canonical method:

unsigned long x = 0x12345678UL;
unsigned char bytes[4];

bytes[0] = (x >> 24) ; // 0x12
bytes[1] = (x >> 16) & 0xFF; // 0x34
bytes[2] = (x >> 8) & 0xFF; // 0x56
bytes[3] = (x ) & 0xFF; // 0x78

Now you can write the bytes to your file. If the output needs to be
big-endian, write from 0 to 3; if little-endian, write from 3 to 0.

Of course, there is no need for the temporary variables if you can
inline the shifting and masking as arguments to the output function, but
the above should make it more clear _to you_ what's going on.

(There are other solutions, but I recommend against using them until you
fully understand how to do it "the hard way" as above.)
I'm also worried about the code being endian specific, the code must
work regardless of whether the machine is little-endian or big-endian,
but I already know how to test which the machine is thanks to the FAQ.

The code above will work regardless of the endianness of the machine.
It does assume 8-bit chars, but a general solution that works with any
valid char width is messy and rarely necessary.
Since it has just occurred to me I should also mention that my int range
is from 0 to potentially the low tens of millions.

MAX_INT is only guaranteed to be 32767; if you need values larger than
that, use long (or long long) int rather than plain int.

S
 
E

Eric Sosman

[...]
I am sorry to say that I simply have no idea whatsoever how to write an
int to a file as a 4 byte big-endian. Can someone show me how please?

Break the 4 byte value into 4 *bytes*. Then, write them
INDIVIDUALLY in Big Endian order.

Ahh yes. That is exactly how far I got on my own. Sorry to be a bit
clueless but I don't know how to accomplish that.

I'm also worried about the code being endian specific, the code must
work regardless of whether the machine is little-endian or big-endian,
but I already know how to test which the machine is thanks to the FAQ.

Don't bother testing: Just use the values.

putc(value & 0xFF, stream);
putc((value >> 8) & 0xFF, stream);
putc((value >> 16) & 0xFF, stream);
putc((value >> 24) & 0xFF, stream);

Works[*] with BigEndian, LittleEndian, MiddleEndian, TightEndian,
EndOverEndian, and NimzoEndian architectures.
Since it has just occurred to me I should also mention that my int range
is from 0 to potentially the low tens of millions.

Although systems with narrow `int' are becoming rare, there
may be a few left. You may wish to take countermeasures, because
if you don't Murphy's Law will surely bite you. Instead of `int'
(which could top out at 32767 on some machines), use a wider type
like `long' (good up to at least 2147483647).[*]

[*] To avoid trouble with negative values, where shifting and
bitwise operations are problematic, prefer an `unsigned' type.
Thanks (and sorry for bothering you guys, I have done several web
searches and can't find any page/post that spells it out for me, I was
surprised it isn't in the FAQ - that usually sorts me out).

Question 10.16 talks about testing for endianness, but also
has a pointer to Question 12.42 and its endian-independent code.
 
E

Eric Sosman

On 3/10/2012 11:00 AM, MS wrote:
[...]
I am sorry to say that I simply have no idea whatsoever how to write an
int to a file as a 4 byte big-endian. Can someone show me how please?

Break the 4 byte value into 4 *bytes*. Then, write them
INDIVIDUALLY in Big Endian order.

Ahh yes. That is exactly how far I got on my own. Sorry to be a bit
clueless but I don't know how to accomplish that.

I'm also worried about the code being endian specific, the code must
work regardless of whether the machine is little-endian or big-endian,
but I already know how to test which the machine is thanks to the FAQ.

Don't bother testing: Just use the values.

putc(value & 0xFF, stream);
putc((value >> 8) & 0xFF, stream);
putc((value >> 16) & 0xFF, stream);
putc((value >> 24) & 0xFF, stream);

Aw, snap: This produces LittleEndian "wire format," and you
wanted BigEndian. Just reverse the four calls -- or read the
code from bottom to top. ;-)
 
M

Malcolm McLean

I am sorry to say that I simply have no idea whatsoever how to write an
int to a file as a 4 byte big-endian. Can someone show me how please?

/*
write a 32 bit big endian integer to file
Params: x - the integer
fp - the open file
Returns: 0 on success, error code on fail
*/
int fput32bigendian(long x, FILE *fp)
{
fputc( (x >> 24) & 0xFF, fp);
fputc( (x >> 16) & 0xFF, fp);
fputc( (x >> 8) & 0xFF, fp);
fputc( x & 0xFF, fp);
return ferror(fp);
}

It doesn't matter whether the machine you are running on is big endian
or little endian. x is a long to avoid an annoying problem of right
shifts that are wider than the type not being defined properly. long
is guarateed at least 32 bits.
On some very esoteric architectures this function will not work
correctly, like one's compement machines. But you almost certainly
don't need to worry about them.
 
L

Lew Pitcher

Hi,

I need some help with something which is a little over my pay grade. :)

The file which I must write has a header followed by a sequence of ints
each of which must be written as a 4 byte big-endian.

The comp.lang.c has advice on finding out whether your machine is
little-endian or big-endian (little-endian in my case) but not on how to
do the kind of operation I need to do.

I am sorry to say that I simply have no idea whatsoever how to write an
int to a file as a 4 byte big-endian. Can someone show me how please?

FWIW, I haven't yet read the other responses.

In my opinion, as a programmer, you shouldn't tackle this as a "how do I
determine the physical implementation of my environment, so that I can
perform a physical transformation".

Instead, you should address your problem as "how do I transform one logical
data structure into another?"

You really don't care what format your source integer is in; it can be
big-endian or little-endian or middle-endian (or any of the other 21
byte-order combinations available for a 4-byte sequence). You have an
integer, that fits between INT_MIN and INT_MAX (or 0 and UINT_MAX) as a
source number.

You want to transform this into a sequence of 8-bit data items, ordered such
that the lowest addressed data item has the highest significance. You don't
want this sequence to exceed 32bits in length (4 8bit quantities).

Depending on whether your source integer is signed or unsigned, you can
simply iteratively modulo 256 the source to determine the lowest
significant octet, save that value, and then divide the source by 256 to
adjust. Do that 4 times for four octets, and abort if the remaining source
value is greater than 0 (signifying that the value can't fit in a 32bit
value). Save the four modulo octets in the correct sequence for your
big-endian value.

On an implementation where CHAR_BIT == 8, this might look like


#include <assert.h>
#include <limits.h>

unsigned int source_integer;
unsigned char big_endian_target[4];
int byte;

assert(CHAR_BIT == 8);
#define EIGHTBITS (UCHAR_MAX + 1)


for (byte = 3; byte > -1; byte--)
{
big_endian_target[byte] = source_integer % EIGHTBITS;
source_integer = source_integer / EIGHTBITS;
}
assert(source_integer == 0);
 
G

Geoff

Hi,

I need some help with something which is a little over my pay grade. :)

The file which I must write has a header followed by a sequence of ints
each of which must be written as a 4 byte big-endian.

The comp.lang.c has advice on finding out whether your machine is
little-endian or big-endian (little-endian in my case) but not on how to
do the kind of operation I need to do.

I am sorry to say that I simply have no idea whatsoever how to write an
int to a file as a 4 byte big-endian. Can someone show me how please?

Many thanks.

What's wrong with using htonl()? Let your implementation worry about
the endianness of your platform. Use ntohl() to convert it when
reading the data back from the file.
 
B

Ben Bacarisse

MS said:
I need some help with something which is a little over my pay grade. :)

The file which I must write has a header followed by a sequence of
ints each of which must be written as a 4 byte big-endian.

The comp.lang.c has advice on finding out whether your machine is
little-endian or big-endian (little-endian in my case) but not on how
to do the kind of operation I need to do.

I am sorry to say that I simply have no idea whatsoever how to write
an int to a file as a 4 byte big-endian. Can someone show me how
please?

void msb_write(unsigned int u, FILE *strm)
{
for (int i = sizeof u - 1; i >= 0; i--)
fputc(u >> (CHAR_BIT * i), strm);
}

CHAR_BIT is defined in limits.h, and you'll have to more the declaration
of i if your compiler does not accept this C99 syntax.

It may seem over the top to reference CHAR_BIT (rather than 8) and use
sizeof u (rather than 4) but I think it makes the code more "obviously"
correct. Also, you can use the same loop code with other sizes of
integer type.

On machines that use odd representations of negative numbers, this won't
write the native bit pattern. In fact it writes the 2's complement
representation because of way C defines the conversion from signed to
unsigned int. This is probably what you want -- file formats that
specify the endianness of the header will almost certainly specify the
representation for negative numbers (if any are expected) and that will
almost certainly be 2's complement.
 
B

Bl0ckeduser

Bl0ckeduser said:
int i = 12345678;
printf("%d\n", (i & 0xFF000000) >> 32);

s/32/24 and s/int/unsigned int/, but anyway the other suggestions
(provided by experts) are no doubt better than mine.
 
M

Malcolm McLean

s/32/24 and s/int/unsigned int/, but anyway the other suggestions
(provided by experts) are no doubt better than mine.
You've got the basic idea, but you've miscalculated the shift. There
are 24 zeroed-out bits in that expression, not 32.
 
M

Morris Keesan

for( i = 3; i >= 0; i-- ) bytes = what % 256, what /= 256;


What ??? Did you do this with a comma operator just to make it hard
to read? If so, it worked. I started to post this as a correction,
before I did a double-take and realized that the assignment has
higher priority than the comma.
 
M

Morris Keesan

Hi,

I need some help with something which is a little over my pay grade. :)

The file which I must write has a header followed by a sequence of ints
each of which must be written as a 4 byte big-endian.

The comp.lang.c has advice on finding out whether your machine is
little-endian or big-endian (little-endian in my case) but not on how to
do the kind of operation I need to do.

I am sorry to say that I simply have no idea whatsoever how to write an
int to a file as a 4 byte big-endian. Can someone show me how please?

Many thanks.
Hm... just reverse the routine below....

int little_endian(char *c){
static union{
int k;
char c[4];
}p;
p.c[0]=c[3];
p.c[1]=c[2];
p.c[2]=c[1];
p.c[3]=c[0];
return p.k;
}

Works only on little-endian machines where sizeof(int) == 4.
Even though the OP states that his machine is little-endian, it seems
unlikely that he would want a solution which is this non-portable.
(And he didn't say whether his machine has 4-byte ints.)
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,743
Messages
2,569,478
Members
44,899
Latest member
RodneyMcAu

Latest Threads

Top