2

Not very skilled in C. This might be just a newbie question.

I am trying to write 3 bytes to file, but end up with 4.

#include <stdio.h>
#include <stdlib.h>

struct a {
  uint8_t x;
  uint16_t y;
};

int main()
{
  struct a record = { 1, 2 };
  FILE *fp = fopen("example.bin", "w");
  fwrite(&record, sizeof(struct a), 1, fp);
  fclose(fp);
}

For some reason I end up with:

$ hexdump -C example.bin
00000000  01 00 02 00                                       |....|
00000004

I was expecting: 01 02 00.

Here is the version of my c compiler in case this is hardware/compiler related.

$ cc --version
Apple LLVM version 9.1.0 (clang-902.0.39.1)
Target: x86_64-apple-darwin17.5.0
Thread model: posix
raupach
  • 3,092
  • 22
  • 30

2 Answers2

5

I am trying to write 3 bytes to file, but end up with 4.

You might be aiming to write to 3 bytes but are actually writing sizeof(struct a), which is likely to 4 because compiler inserted a byte of padding for alignment. Perhaps you are assuming size of a structure is equal to the sum of sizes of its members and failed to account for possible padding.

In general, compiler is free to insert padding in a way for alignment purposes (except there can't be any padding before the first member of the struct).

If you write the individual members, you'd see the expected output:

  fwrite(&record.x, sizeof record.x, 1, fp);
  fwrite(&record.y, sizeof record.y, 1, fp);

P.S.: Make sure you error check all the functions that could fail (fopen, fwrite, etc).

P.P
  • 117,907
  • 20
  • 175
  • 238
  • Thanks, now I know a litte bit more about data alignment. – raupach Apr 18 '18 at 11:00
  • Just a note about `__attribute__((packed))`: It *can be* useful under some circumstances but generally it should be avoided. If an architecture doesn't support unaligned accesses, packed structs would fail (typically bus error) or frequent faults might affect performance. – P.P Apr 18 '18 at 11:28
  • What are the options on architectures with unaligned accesses? Lets say I am stuck with reading and writing these kind of structs? – raupach Apr 18 '18 at 11:53
  • 1
    You can "manually" pack it by rearranging the members appropriately or using only fixed size variables (so that compiler won't introduce padding). Or insert padding yourself so that you know the precise size of the struct on all archs. Might be useful to read: http://www.catb.org/esr/structure-packing/ – P.P Apr 18 '18 at 11:57
0

Structs are often padded by the compiler - empty space has been inserted after x so that y is aligned to a 16-bit boundary.

GCC offers __attribute__((packed)) to disable this behaviour; see these docs

user234461
  • 1,133
  • 12
  • 29