Casting Char[4] into int*

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Chlikaflok@gmail.com

    #1

    Casting Char[4] into int*

    See, I have this code, I'm trying to open and run a MIDI file, and I'm
    parsing the header to check it's integrity :

    // Parse header info.
    char chunkType[4];
    char buffer[4];
    SINT32 *length;
    if ( !file_.read( chunkType, 4 ) ) goto error;
    if ( !file_.read( buffer, 4 ) ) goto error;

    length = (SINT32 *) &buffer;
    if ( strncmp( chunkType, "MThd", 4 ) || ( *length != 6 ) )
    {Error msgs and stuff}

    SINT32 is a typedef for signed int

    Using a perfectly good midi file, this segment of code should go right
    past the IF block, because the buffer char array should contain ([0],
    [0],[0],[6]), which it does. But when I evaluate the length expression
    in the IF clause, the value is exactly and always : 100663296.

    As I understand it, the 4-byte char array contains "00000006", which
    when cast to int should read "6", correct me if I'm wrong. Using
    buffer[3]instead of the *length evaluation in the IF resolves the
    problem, but that way of using the buffer data is used all over the
    library I'm using and I believe it was done that way for a reason.

    Any help would be welcome,
    Thx in advance for at least reading this,
    Chlikaflok.

  • p.lepin@ctncorp.com

    #2
    Re: Casting Char[4] into int*

    On Apr 2, 5:02 pm, Chlikaf...@gmai l.com wrote:
    // Parse header info.
    char chunkType[4];
    char buffer[4];
    SINT32 *length;
    if ( !file_.read( chunkType, 4 ) ) goto error;
    if ( !file_.read( buffer, 4 ) ) goto error;
    >
    length = (SINT32 *) &buffer;
    if ( strncmp( chunkType, "MThd", 4 ) || ( *length != 6 ) )
    {Error msgs and stuff}
    >
    SINT32 is a typedef for signed int
    >
    Using a perfectly good midi file, this segment of code
    should go right past the IF block, because the buffer
    char array should contain ([0], [0],[0],[6]), which it
    does. But when I evaluate the length expression in the IF
    clause, the value is exactly and always : 100663296.
    >
    As I understand it, the 4-byte char array contains
    "00000006", which when cast to int should read "6",
    correct me if I'm wrong.
    I believe you are wrong. That depends on the endianness of
    your platform. Assuming your char is 8-bit long, and the
    last char being most significant, the result of this
    conversion should be 6 * ( 2 ^ 24 ) = 100663296, which is
    precisely what you're getting.

    Anyway, I'm not sure this is even topical in this group;
    you would probably get more help in a platform-specific
    group for your platform.

    --
    Pavel Lepin

    Comment

    • Chlikaflok@gmail.com

      #3
      Re: Casting Char[4] into int*

      On Apr 2, 10:13 am, p.le...@ctncorp .com wrote:
      On Apr 2, 5:02 pm, Chlikaf...@gmai l.com wrote:
      >
      >
      >
      >
      >
      // Parse header info.
      char chunkType[4];
      char buffer[4];
      SINT32 *length;
      if ( !file_.read( chunkType, 4 ) ) goto error;
      if ( !file_.read( buffer, 4 ) ) goto error;
      >
      length = (SINT32 *) &buffer;
      if ( strncmp( chunkType, "MThd", 4 ) || ( *length != 6 ) )
      {Error msgs and stuff}
      >
      SINT32 is a typedef for signed int
      >
      Using a perfectly good midi file, this segment of code
      should go right past the IF block, because the buffer
      char array should contain ([0], [0],[0],[6]), which it
      does. But when I evaluate the length expression in the IF
      clause, the value is exactly and always : 100663296.
      >
      As I understand it, the 4-byte char array contains
      "00000006", which when cast to int should read "6",
      correct me if I'm wrong.
      >
      I believe you are wrong. That depends on the endianness of
      your platform. Assuming your char is 8-bit long, and the
      last char being most significant, the result of this
      conversion should be 6 * ( 2 ^ 24 ) = 100663296, which is
      precisely what you're getting.
      >
      Anyway, I'm not sure this is even topical in this group;
      you would probably get more help in a platform-specific
      group for your platform.
      >
      --
      Pavel Lepin- Hide quoted text -
      >
      - Show quoted text -
      Wow! Thank you, it now works, you were right, I had seen the
      endianness algorithms in my code, but it didn't occur to me that I had
      forgotten to define the endianness in my precompiler.

      And sorry for not having posted in the right group, but up until your
      answer I wasn't aware that the error was platform-specifications
      oriented, so I couldn't post in the right group, so I chose to go to
      the most appropriate : the c++ group for c++ problems, no?

      Anyway, I'll try to be more wary of the topicality of my questions in
      the future, and thanks again!

      Cheers,
      Chlikaflok.

      Comment

      • Victor Bazarov

        #4
        Re: Casting Char[4] into int*

        Chlikaflok@gmai l.com wrote:
        See, I have this code, I'm trying to open and run a MIDI file, and I'm
        parsing the header to check it's integrity :
        >
        // Parse header info.
        char chunkType[4];
        char buffer[4];
        SINT32 *length;
        if ( !file_.read( chunkType, 4 ) ) goto error;
        if ( !file_.read( buffer, 4 ) ) goto error;
        >
        length = (SINT32 *) &buffer;
        if ( strncmp( chunkType, "MThd", 4 ) || ( *length != 6 ) )
        {Error msgs and stuff}
        >
        SINT32 is a typedef for signed int
        >
        Using a perfectly good midi file, this segment of code should go right
        past the IF block, because the buffer char array should contain ([0],
        [0],[0],[6]), which it does. But when I evaluate the length expression
        in the IF clause, the value is exactly and always : 100663296.
        >
        As I understand it, the 4-byte char array contains "00000006", which
        when cast to int should read "6", correct me if I'm wrong. Using
        buffer[3]instead of the *length evaluation in the IF resolves the
        problem, but that way of using the buffer data is used all over the
        library I'm using and I believe it was done that way for a reason.
        Could it be you're running into the endianness conflict here?

        100663296 is 0x06000000, i.e. 6 shifted left 24 positions. What you
        need is to rearrange the bytes after reading them before casting them
        to your 'SINT32', or simply make your SINT32 out of the bytes you got
        using shift and OR. It is a common problem with reading files designed
        to be read on different platforms.

        V
        --
        Please remove capital 'A's when replying by e-mail
        I do not respond to top-posted replies, please don't ask


        Comment

        • Victor Bazarov

          #5
          Re: Casting Char[4] into int*

          Chlikaflok@gmai l.com wrote:
          On Apr 2, 10:13 am, p.le...@ctncorp .com wrote:
          >On Apr 2, 5:02 pm, Chlikaf...@gmai l.com wrote:
          >> // Parse header info.
          >> char chunkType[4];
          >> char buffer[4];
          >> SINT32 *length;
          >> if ( !file_.read( chunkType, 4 ) ) goto error;
          >> if ( !file_.read( buffer, 4 ) ) goto error;
          >>
          >> length = (SINT32 *) &buffer;
          >> if ( strncmp( chunkType, "MThd", 4 ) || ( *length != 6 ) )
          >> {Error msgs and stuff}
          >>
          >>SINT32 is a typedef for signed int
          >[..]
          >>
          >Anyway, I'm not sure this is even topical in this group;
          >you would probably get more help in a platform-specific
          >group for your platform.
          >[..]
          >
          And sorry for not having posted in the right group, but up until your
          answer I wasn't aware that the error was platform-specifications
          oriented, so I couldn't post in the right group, so I chose to go to
          the most appropriate : the c++ group for c++ problems, no?
          You have posted in the right newsgroup, don't worry about it.
          [..]
          V
          --
          Please remove capital 'A's when replying by e-mail
          I do not respond to top-posted replies, please don't ask


          Comment

          • James Kanze

            #6
            Re: Casting Char[4] into int*

            On Apr 2, 4:02 pm, Chlikaf...@gmai l.com wrote:
            See, I have this code, I'm trying to open and run a MIDI file, and I'm
            parsing the header to check it's integrity :
            // Parse header info.
            char chunkType[4];
            char buffer[4];
            SINT32 *length;
            if ( !file_.read( chunkType, 4 ) ) goto error;
            if ( !file_.read( buffer, 4 ) ) goto error;
            length = (SINT32 *) &buffer;
            if ( strncmp( chunkType, "MThd", 4 ) || ( *length != 6 ) )
            {Error msgs and stuff}
            SINT32 is a typedef for signed int
            Which may be larger than 4 bytes, in which case, you have a real
            problem.
            Using a perfectly good midi file, this segment of code should go right
            past the IF block, because the buffer char array should contain ([0],
            [0],[0],[6]), which it does. But when I evaluate the length expression
            in the IF clause, the value is exactly and always : 100663296.
            And on other platforms, it may give 0, or 393216, or even cause
            a crash.
            As I understand it, the 4-byte char array contains "00000006", which
            when cast to int should read "6", correct me if I'm wrong.
            You're wrong. It's completely undefined behavior. Even if your
            platform uses four byte integers, it depends on the byte order:
            I've seen at least three different arrangements in my own
            experience (which would result in 6, 393216 or 100663296).
            Using
            buffer[3]instead of the *length evaluation in the IF resolves the
            problem, but that way of using the buffer data is used all over the
            library I'm using and I believe it was done that way for a reason.
            Maybe the reason was that the author didn't know C or C++. Or
            had a tormented way of thinking. If I want to verify that four
            bytes contain, successively, 0, 0, 0 and 6, I'll do just that.
            Say with:

            static char const ref[ 4 ] = { 0, 0, 0, 6 } ;
            if ( memcmp( ref, length, 4 ) != 0 ) {
            // error...
            }

            or (more likely in new code):
            static char const ref[ 4 ] = { 0, 0, 0, 6 } ;
            if ( ! std::equal( begin( ref ), end( ref ), length ) ) {
            // error...
            }

            In your case, I'd probably work on the whole 8 byte chunk in one
            go, comparing with a reference:
            static char const ref[ 8 ] = { 'M', 'T', 'h', 'd', 0, 0, 0,
            6 } ;
            I might even use the numerical values for the characters, since
            what I'm looking for is a specific content, regardless of the
            code set I use in my own program.

            --
            James Kanze (GABI Software) email:james.kan ze@gmail.com
            Conseils en informatique orientée objet/
            Beratung in objektorientier ter Datenverarbeitu ng
            9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

            Comment

            Working...