Fread(): Reading From A File (without Alignment) Results In Skipping Of Bytes
I have a file and using C I want to read the contents of it using fread() (from stdio.h) and write it into the members of a struct. (In my case there is a 2 byte int at the start followed by a 4 byte int.) But after writing the contents of the file correctly into the first two byte variable of the struct, it skips two bytes before continuing with the second four byte variable.
To demonstrate, I have created a 16 byte file to read from. In Hex it looks like this (Little-endian):
22 11 66 55 44 33 11 11 00 00 00 00 00 00 00 00
With the following code I expect the first variable, twobytes
, to be 0x1122
and the second, fourbytes
, to be 0x33445566
. But instead it prints:
twobytes: 0x1122
fourbytes: 0x11113344
sizeof(FOO) = 8
&foo : 0061FF14
&foo.two : 0061FF14
&foo.four: 0061FF18
Skipping bytes 3 and 4 (0x66
& 0x55
). Code:
#include <stdio.h>
#include <stdint.h>
int main(void) {
FILE* file = fopen("216543110.txt", "r");
if (file==NULL) { return 1; }
typedef struct
{
uint16_t twobytes;
uint32_t fourbytes;
}__attribute__((__packed__)) // removing this attribute or just the underscores around packed does not change the outcome
FOO;
FOO foo;
fread(&foo, sizeof(FOO), 1, file);
printf("twobytes: 0x%x \n", foo.twobytes);
printf("fourbytes: 0x%x \n\n", foo.fourbytes);
printf("sizeof(FOO) = %d\n", sizeof(FOO));
printf("&foo : %p\n", &foo);
printf("&foo.two : %p\n", &foo.twobytes);
printf("&foo.four: %p\n", &foo.fourbytes);
fclose(file);
return 0;
}
Using a struct with two same size integers works as expected.
So: Using fread() to write into different size variables causes skipping bytes:
22 11
.. ..
44 33 11 11
...
instead of
22 11
66 55 44 33
...
I am aware that something about byte alignment is playing a role here, but how does that affect the reading of bytes? If C wants to add padding to the structs, how does that affect the reading from a file?
I don't care if C is storing the struct members as
22 11
.. ..
66 55 44 33
...
or
22 11
66 55 44 33
...
,
I'm confused about why it fails to read my file correctly.
Also, I am using gcc version 6.3.0 (MinGW.org GCC-6.3.0-1)
Answer
On GCC, when targetting x86 platforms, the
__attribute__((__packed__))
only works on structs with
However, when targetting Microsoft Windows platforms, the default attribute for structs is
__attribute__((ms_struct))
.
Therefore, I see three ways to accomplish what you want:
- Use the compiler command-line option
-mno-ms-bitfields
to make all structs default to__attribute__((gcc_struct))
. - Explicitly use
__attribute__((gcc_struct))
on your struct. - Use
#pragma pack
instead of__attribute__((__packed__))
.
Also, as pointed out in the answer by @chqrlie, there are some other things not ideal in your code. Especially when reading binary data, you should normally open the file in binary mode and not text mode, unless you know what you are doing (which you possibly are, since the file has a .txt
extension).
Related Questions
- → OctoberCMS Backend Loging Hash Error
- → "failed to open stream" error when executing "migrate:make"
- → OctoberCMS - How to make collapsible list default to active only on non-mobile
- → Create plugin that makes objects from model in back-end
- → October CMS Plugin Routes.php not registering
- → OctoberCMS Migrate Table
- → How to install console for plugin development in October CMS
- → OctoberCMS Rain User plugin not working or redirecting
- → October CMS Custom Mail Layout
- → October CMS - How to correctly route
- → October CMS create a multi select Form field
- → How to update data attribute on Ajax complete
- → October CMS - Conditionally Load a Different Page