TheJach.com

Jach's personal blog

(Largely containing a mind-dump to myselves: past, present, and future)
Current favorite quote: "Supposedly smart people are weirdly ignorant of Bayes' Rule." William B Vogt, 2010

Brief Intro to Memory Mapping Into Structs

Learning how to memory map was a frustrating topic to hunt down, despite how easy it really is. First I'll share my main source, then get to what I was doing. For a great intro to memory mapping, follow that link. It will explain the code below while I'm just going to show it and tell what it does on a high level.


#include <unistd.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <malloc.h>

struct GamColor
{
unsigned char d_red;
unsigned char d_green;
unsigned char d_blue;
unsigned char x_pad;
};

struct GamColorMap
{
char d_name[16];
struct GamColor d_map[16];
unsigned int d_ID;
};

int main(void) {

int fd, offset;
void *data;
struct stat sbuf;

if ( (fd = open("ocean.thm", O_RDONLY)) == -1) {
perror("open");
exit(1);
}

if (stat("ocean.thm", &sbuf) == -1) {
perror("stat");
exit(1);
}

offset = 0;

data = mmap((caddr_t)0, sbuf.st_size, PROT_READ, MAP_PRIVATE, fd, offset);
if ((caddr_t)data == (caddr_t)(-1)) {
perror("mmap");
exit(1);
}

struct GamColorMap *thm = malloc(sizeof(struct GamColorMap));

memcpy(thm, data, sizeof(struct GamColorMap));
offset += sizeof(struct GamColorMap);

int i;
for (i = 0; i < 16; i++) {
struct GamColor *c = &thm->d_map[i];
printf("%d %d %d\n", c->d_red, c->d_green, c->d_blue);
}

free(thm);
munmap(data, sbuf.st_size);

return 0;
}


So what the crap's going on? I have a binary file called ocean.thm, which consists of a name (maximum 16 characters, it's padded with 0's at the end), the 16 RGBx colors (the x is to keep things aligned on four byte blocks), and a 4-byte ID that is set to 0 and intended to be handled at runtime (which it's not in this example). "data" is a void pointer so I can throw whatever in there, however if you're doing pointer arithmetic (e.g. (data + offset)), make sure you cast data as a character pointer so it will always step one-byte. A use not shown is the theme file containing several ascii sprites, with each sprite containing its own frames as well. So it needs to know how much data to grab between sprites, which you can accomplish with some math involving sizeof() and total_frames * sprite_width * sprite_height * sprite_data_size. You need to keep track of the offset there, and you can loop while the offset is less than sbuf.st_size.

Other than that, the code is pretty much straightforward. It seriously took me longer than it should have to find the link I gave above: I just wanted some sample mmap code that read from a file, damn it! Anyway, it's here to help anyone who may need it.

ADDENDUM

It occurred to me that one of the reasons memory mapping into a struct seemed initially confusing was because of an initial confusement of what a struct even is: a struct is like an array with different types and names for indices. If you have a struct with int x, int y, int z in it, the struct's size is sizeof(int) * 3 bytes. Ints are usually 4 bytes, so the whole struct is 12 bytes. If you have a blob of memory 12 bytes wide, you can memcpy it directly into that struct, and then read it out in 4-byte chunks as integers. This means it's important to pad your binary data if you're generating a file to be read by C from a higher language. In Python, import struct and use pack/unpack to help out.


Posted on 2010-03-11 by Jach

Tags: c, programming

Permalink: https://www.thejach.com/view/id/81

Trackback URL: https://www.thejach.com/view/2010/3/brief_intro_to_memory_mapping_into_structs

Back to the top

Back to the first comment

Comment using the form below

(Only if you want to be notified of further responses, never displayed.)

Your Comment:

LaTeX allowed in comments, use $$\$\$...\$\$$$ to wrap inline and $$[math]...[/math]$$ to wrap blocks.