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

Discussion in 'C Programming' started by MS, Mar 10, 2012.

  1. MS

    MS Guest

    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.
    MS, Mar 10, 2012
    #1
    1. Advertising

  2. MS

    Don Y Guest

    On 3/10/2012 11:00 AM, MS wrote:
    > 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.
    Don Y, Mar 10, 2012
    #2
    1. Advertising

  3. MS

    MS Guest

    On 10/03/12 18:11, Don Y wrote:
    > On 3/10/2012 11:00 AM, MS wrote:
    >> 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.


    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).
    MS, Mar 10, 2012
    #3
  4. MS

    Bl0ckeduser Guest

    MS wrote:
    > 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
    Bl0ckeduser, Mar 10, 2012
    #4
  5. MS

    Tim Rentsch Guest

    MS <ms@no_spam_thanks.com> writes:

    > 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).
    Tim Rentsch, Mar 10, 2012
    #5
  6. MS

    Sjouke Burry Guest

    MS <ms@no_spam_thanks.com> wrote in news:mFM6r.21733$di4.7072
    @newsfe14.ams2:

    > 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;
    }
    Sjouke Burry, Mar 10, 2012
    #6
  7. On Sat, 10 Mar 2012 13:00:50 -0500, MS <ms@no_spam_thanks.com> wrote:

    > 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.
    --
    Morris Keesan --
    Morris Keesan, Mar 10, 2012
    #7
  8. On 10-Mar-12 12:36, MS wrote:
    > On 10/03/12 18:11, Don Y wrote:
    >> On 3/10/2012 11:00 AM, MS wrote:
    >>> 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.

    >
    > 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

    --
    Stephen Sprunk "God does not play dice." --Albert Einstein
    CCIE #3723 "God is an inveterate gambler, and He throws the
    K5SSS dice at every possible opportunity." --Stephen Hawking
    Stephen Sprunk, Mar 10, 2012
    #8
  9. MS

    Eric Sosman Guest

    On 3/10/2012 1:36 PM, MS wrote:
    > On 10/03/12 18:11, Don Y wrote:
    >> 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);

    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.

    --
    Eric Sosman
    d
    Eric Sosman, Mar 10, 2012
    #9
  10. MS

    Eric Sosman Guest

    On 3/10/2012 3:20 PM, Eric Sosman wrote:
    > On 3/10/2012 1:36 PM, MS wrote:
    >> On 10/03/12 18:11, Don Y wrote:
    >>> 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. ;-)

    --
    Eric Sosman
    d
    Eric Sosman, Mar 10, 2012
    #10
  11. On Mar 10, 6:00 pm, MS <ms@no_spam_thanks.com> 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?
    >


    /*
    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.
    Malcolm McLean, Mar 10, 2012
    #11
  12. MS

    Lew Pitcher Guest

    On Saturday 10 March 2012 13:00, in comp.lang.c, ms@no_spam_thanks.com
    wrote:

    > 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);

    --
    Lew Pitcher
    Lew Pitcher, Mar 10, 2012
    #12
  13. MS

    Geoff Guest

    On Sat, 10 Mar 2012 18:00:50 +0000, MS <ms@no_spam_thanks.com> wrote:

    >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.
    Geoff, Mar 10, 2012
    #13
  14. MS <ms@no_spam_thanks.com> writes:

    > 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.

    --
    Ben.
    Ben Bacarisse, Mar 10, 2012
    #14
  15. MS

    Ike Naar Guest

    On 2012-03-10, Morris Keesan <> wrote:
    > unsigned long int ltemp = intvalue;
    > for (int i = 0; i < 3; ++i)


    s/3/4/ (assuming you want to output four bytes)

    > fputc((intvalue >> (8 * (3 - i))) & 0xff, file);


    s/intvalue/ltemp/
    Ike Naar, Mar 10, 2012
    #15
  16. MS

    Bl0ckeduser Guest

    Bl0ckeduser wrote:
    > 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.
    Bl0ckeduser, Mar 10, 2012
    #16
  17. On Mar 10, 9:33 pm, Bl0ckeduser <> wrote:
    > Bl0ckeduser wrote:
    > > 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.
    >

    You've got the basic idea, but you've miscalculated the shift. There
    are 24 zeroed-out bits in that expression, not 32.

    --
    Basic Algorithms - understand how JPEG files work, from the ground up,
    and much more
    http://www.malcolmmclean.site11.com/www
    Malcolm McLean, Mar 10, 2012
    #17
  18. Stephen Sprunk <> writes:
    [...]
    > MAX_INT is only guaranteed to be 32767;

    [...]

    and is spelled INT_MAX.

    --
    Keith Thompson (The_Other_Keith) <http://www.ghoti.net/~kst>
    Will write code for food.
    "We must do something. This is something. Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"
    Keith Thompson, Mar 10, 2012
    #18
  19. On Sat, 10 Mar 2012 14:44:13 -0500, Tim Rentsch <>
    wrote:

    > 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.
    --
    Morris Keesan --
    Morris Keesan, Mar 10, 2012
    #19
  20. On Sat, 10 Mar 2012 14:44:38 -0500, Sjouke Burry <s@b> wrote:

    > MS <ms@no_spam_thanks.com> wrote in news:mFM6r.21733$di4.7072
    > @newsfe14.ams2:
    >
    >> 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.)
    --
    Morris Keesan --
    Morris Keesan, Mar 10, 2012
    #20
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. hicham
    Replies:
    2
    Views:
    9,008
    dxcoder
    Jul 2, 2003
  2. Ernst Murnleitner

    float: IEEE, big endian, little endian

    Ernst Murnleitner, Jan 13, 2004, in forum: C++
    Replies:
    0
    Views:
    851
    Ernst Murnleitner
    Jan 13, 2004
  3. invincible

    Little Endian to Big Endian

    invincible, Jun 14, 2005, in forum: C++
    Replies:
    9
    Views:
    14,325
    Old Wolf
    Jun 14, 2005
  4. invincible
    Replies:
    1
    Views:
    537
    red floyd
    Jun 14, 2005
  5. Replies:
    5
    Views:
    333
    Stephen Sprunk
    Aug 31, 2006
Loading...

Share This Page