Inconsistent Binary Data or Condition Statement Ch

2019-08-12 09:28发布

Really having some trouble even phrasing the problem. What's happening is I'm reading and storing an entire binary file into a uint32_t*. Then checking for the start of the segment of data I need. However, adding a check to just make sure I haven't passed over the array changes where the start of the segment is and I have no idea why.

#include <iostream>
#include <string.h>
#include <typeinfo>
#include <fstream>
#include <vector>
#include <stdint.h>
#include <stdexcept>
using namespace std;

int* binmem = new int[32]; 
streampos size; // size of memblock 
int blocklength; // length memblock
uint32_t * memblock; // all data
int startpos; 
int endpos;  
int x;

void NewParticle() {
    startpos = 0;
    while (memblock[startpos]!= 0xff000000) { // 4278190080
        if (startpos > blocklength) {
            //cout << "nah";
            //x++;
            throw invalid_argument("No start of particle");
        }
        startpos++;
    }
}
int main(int argc, const char *argv[]) {
    ifstream file(argv[0], ios::in | ios::binary | ios::ate);
    if (file.is_open()) {
        size = file.tellg();
        blocklength = (size / 4) + (size % 4 == 0 ? 0 : 1);
        memblock = new uint32_t[size / 4 + (size % 4 == 0 ? 0 : 1)];
        file.seekg(0, ios::beg);
        file.read(reinterpret_cast<char*>(memblock), size);
        file.close();
        NewParticle();
    } else
        cout << "Unable to open file";
    return 0;
}

startpos then varies depending on what condition statement I add into NewParticle(), eg. throwing the exception gives 1109 where as taking the condition out completely gives 812. Using the "nah" makes the while loop run forever and using the x++ statement causes a segment fault... Any idea how these could possibly be changing things? Thank you

1条回答
叼着烟拽天下
2楼-- · 2019-08-12 09:57

You code seems to work if your input is a valid file.

As @RetiredNinja pointed out, possible problems are:

  1. Using argv [0] instead of argv [1].

    argv [0] will typically point to the name of the executable, which is probably not the file you wish to parse. If you are trying to parse your currently running executable to find your particles, then you have a bad design. So make this change:

    ifstream file(argv[1], ios::binary | ios::ate);
    

    Run your program like this (for Linux):

    ./myprogram file.bin
    

    or (for Windows):

    .\myprogram.exe file.bin
    

    Or change the default command line arguments in your IDE if you're trying to debug your program.

  2. The value 0xFF000000 is not on an aligned four-byte boundary.

    For instance, the value could be spread across two uint32_ts in your array. This situation is a bit more complicated. You will have to basically iterate through your uint32_t array with a char* and look for a 0xFF and see if you can find 3 0x00 before or after it (depending on endianness).

The rest of this answer is just some minor recommendations. You can ignore the rest of this if you want. All of this below assumes problem 2 does not exist.

Here is how I generated a test file for your code:

void createBinFile (const std::string &file_name)
{
    // Some random data to use.
    const uint32_t sample_data [] = {
        0x000000cc,
        0x0000dd00,
        0x00ee0000,
        0xff000000,
        0x00000011,
        0x00002200,
        0x00330000,
        0x44000000,
    } ;

    // Write some binary data.
    std::ofstream file (file_name, std::ios::binary) ;
    file.write (reinterpret_cast <const char *> (sample_data), sizeof (sample_data)) ;
}

Managing your own memory is unnecessary. Here's a way to use a std::vector <uint32_t> instead of a raw uint32_t* array:

std::vector <uint32_t> loadBinFile (const std::string &file_name)
{
    std::ifstream file (file_name, std::ios::binary | std::ios::ate) ;

    std::streampos size = file.tellg () ;
    file.seekg (0, std::ios::beg) ;

    unsigned padding = (size % sizeof (uint32_t) == 0) ? 0 : 1 ; // or throw exception 
    unsigned vec_size = size / sizeof (uint32_t) + padding ;

    std::vector <uint32_t> data (vec_size) ;
    file.read (reinterpret_cast <char*> (&data[0]), size) ;

    return data ;
}

And here's a quick driver that shows how to find your 0xFF000000 value. This requires you to #include <algorithm> for std::find().

int main (int argc, char *argv [])
{
    const std::string file_name = argv [1] ;

    std::vector <uint32_t> data = loadBinFile (file_name) ;

    const uint32_t sentry_value = 0xff000000 ;

    typedef std::vector <uint32_t>::const_iterator const_iterator ;
    const_iterator citer = std::find (data.begin (), data.end (), sentry_value) ;

    if (citer != data.end ()) {
        std::cout << "Particle found!" "\n" ;
    }

    else {
        std::cout << "Particle not found!" "\n" ;
    }

    return 0 ;
}
查看更多
登录 后发表回答