2

I'm reading structure in file *stl, but the structure is:

typedef struct
{
    float x;
    float y;
    float z;
} point;
typedef struct 
{
    point normal_vector; //12 bytes
    point p1; //12 bytes
    point p2; //12 bytes
    point p3; //12 bytes
    short int notuse; //2 bytes
} triangle;

sizeof(triangle) is 52—12+12+12+12+2+...2 (I don't know where the last 2 comes from?) The size of each unit in file *stl is 50 (not multiple of 4).

How can I reduce the size of structure to read file (from 52 to 50)?

Thank you.

Maxime Chéramy
  • 17,761
  • 8
  • 54
  • 75

3 Answers3

1

Extra two bytes are coming due to padding. Padding is to align the structure with 4 bytes boundary (your word size may be 32 bits, it can vary for 64-bits).

In file, you have stored 50 bytes per structure. So, you can read those 50 bytes and assign the value to each member one by from 50 bytes. Code will look like

Char readbuf[50];

//Read the 50 bytes into the buffer readbuf.

 triangle t;

 t.normal_vector.x  = (float *)readbuf;
 t.normal_vector.y  = (float *)(readbuf + sizeof(float));
 t.normal_vector.z  = (float *)(readbuf + 2*sizeof(float));
 t.p1.x             = (float *)(readbuf + 3*sizeof(float));

//and so on for other members.

Please note that this has byte alignment issue and same programme may not work on big endian machine. So, be wary of storing binary data directly without any rule or encoding.

doptimusprime
  • 9,115
  • 6
  • 52
  • 90
1

With GCC/G++ you could do this to pack your structure:

typedef struct 
{
    point normal_vector; //12 bites
    point p1; //12 bites
    point p2; //12 bites
    point p3; //12 bites
    short int notuse; //2 bites
} __attribute__((packed)) triangle;
Elias Kuiter
  • 93
  • 1
  • 8
1

A way to be preferred over reading the struct - whose memory layout can vary, as you see - as it is and reducing its size could be the way to go.

That said, you can read the file in large blocks and cut the data in the parts you need. Then you read out field for field and put the data into your target array. Something like

float read_float(void ** data) {
    float ** fp = data;
    float ret = **fp; (*fp)++;
    return ret;
}

point read_point(void ** data) {
    point ret;
    ret.x = read_float(data);
    ret.y = read_float(data);
    ret.z = read_float(data);
    return ret;
}

int16_t read16(void ** data) {
    int16_t ** i16p = data;
    int16_t ret = **i16p; (*i16p)++;
    return ret;
}

point read_triangle(void ** data) {
    triangle ret;
    ret.normal_vector = read_point(data);
    ret.p1 = read_point(data);
    ret.p2 = read_point(data);
    ret.p3 = read_point(data);
    ret.notuse = read_int16(data); // using short int is not portable as well as its size could vary...
    return ret;
}

void * scursor = source_array; // which would be a char array
while (scursor < source_array + sizeof(source_array)) {
    // make sure that there are enough data present...
    target[tcursor++] = read_triangle(&scursor); // the scursor will be advanced by the called function.
}

This way could as well - with certain enhancements - be used to keep e. g. the endianness of your numbers the same - which would be preferrably big endian on files intended to be interchanged between platforms. The changes to read16 would be small, the changes to read_float a bit bigger, but still doable.

glglgl
  • 89,107
  • 13
  • 149
  • 217
  • @gigigi -- Why did you assign 'fp' and 'i16p'? They don't appear to get used. And what do you mean by "the same"? The interpretation of the data in a file will still be platform dependent in your solution. Reading a big-endian-formatted file on a little-endian architecture will give incorrect results. – willus Nov 02 '13 at 11:25
  • 1
    @willus (or am I supposed to call you wiiius? :-) ) Now they are used, thanks for pointing out. Right now, indeed the interpretation is platform-dependent, but the way to platform-independence is now very short. – glglgl Nov 02 '13 at 13:27
  • Sorry. I was using an iPad, the font was small, and my eyes are not what they used to be. Feel free to call me wiiius! :) BTW, why does the comment system sometimes not seem to accept "@username" at the beginning of a line? – willus Nov 02 '13 at 15:34
  • @willus According to my experience, if you comment an answer and the answerer didn't comment yet, he is not accepted automatially because he'd get notified nevertheless. – glglgl Nov 02 '13 at 16:49