mmap reading stale array of integers from an file

2019-09-09 10:47发布

问题:

I'm trying to read matrix of integers from file using mmap. If I receive it as char pointer from mmap function, I see everything correct but if I use int pointer, it gives me stale data. Problem with using char pointer is that I need to parse whole string using strtok or something else and get integers one by one. My matrix size is going to be 4k * 4k hence making that many calls to sscanf and strtok is not efficient. Please look at the program and output

#define INTS 3 * 3

int main()
{

    FILE* in = fopen("int_file", "rb");
    int* ints = (int*)mmap(0, INTS * sizeof(int),
                      PROT_READ, MAP_FILE | MAP_PRIVATE, fileno(in),0);
    fclose(in);
    for(int i = 0; i < INTS; ++i) { 
        std::cout << ints[i] << std::endl;
    }
    munmap(ints, INTS * sizeof(int));
    return 0;
}

Contents of int_file is

510 20 30 40 50 60 100 200 10000

Output

540029237 857747506 808716848 540030240 822751286 84097028

回答1:

The ACSII value of the text is getting printed.

Your text seems like:

510 20 30...

From ASCII table (to explain what I want to tell):

No.       ASCII (hex)

Space ->   20
0     ->   30
1     ->   31
2     ->   32
3     ->   33
5     ->   35

int is 4 byte in size, so, taking first 4 bytes:

Converting to ASCII, "510 " gives "35 31 30 20" in memory which is 0x20303135 (540029237 as decimal) for a little endian machine. Similarly, next 4 bytes "20 3" gives 0x33203032(857747506 as decimal). This is what you are getting.

You need to convert each ACSII to integer using atoi() or similar, in this case.

But you may store your integers as their binary value itself rather than keeping it as ASCII. The file will not be human readable but it will do your purpose.



回答2:

Reading it as int * is possible if the data in file is stored from int array or continuous memory through calloc. Writer should look like,

#include <iostream>
#include <sys/mman.h>
#include <stdio.h>

using namespace std;

int inst[] = {510, 20, 30, 40, 50, 60, 100, 200, 10000 };

#define INTS 3 * 3

int main()
{
        FILE* out = fopen("int_file", "wb");  // Error checks are needed
        char *ptr = (char *) inst;
        fwrite( ptr, sizeof( int ), INTS, out );
        fclose( out);
        return 0;
}

Then the reader can read using mmap like as it is in your code,

#include <iostream>
#include <sys/mman.h>
#include <stdio.h>

using namespace std;

#define INTS 3 * 3

int main()
{

    FILE* in = fopen("int_file", "rb");    // Error checks are needed
    int* ints = (int*)mmap(0, INTS * sizeof(int),
                    PROT_READ, MAP_FILE | MAP_PRIVATE, fileno(in),0);
    fclose(in);
    for(int i = 0; i < INTS; ++i) {
            std::cout << ints[i] << std::endl;
    }
    munmap(ints, INTS * sizeof(int));
    return 0;
}

If not stored from array or continuous memory, then using char * and strtok and atoi is the best solution..



标签: c++ linux mmap