Entangled with reading the structure of the file and placing them in memory. As I know, the compiler performs data alignment to increase performance. I am writing a program to read (read only) the file structure of fat16 (for informational purposes only). here is the structure itself

struct struct_fat16 { char Instruction[3]; char IdOs[8]; uint16_t BytesPerSector; uint8_t SectorPerCluster; uint16_t ReservedSectors; uint8_t NubmerOfFATs; uint16_t RootEntries; uint16_t TotalSectors; uint8_t MediaDescriptor; uint16_t SectorPerFat; uint16_t SectorPerTrack; uint16_t Heads; uint32_t HiddenSectors; uint32_t BigTotalSectors; uint8_t PhysicalDiskNumber; uint8_t CurrentHead; uint8_t Signature; uint32_t VolumeSerialNumber; char VolumeLabel[11]; char SystemID[8]; char CodeBootLoader[448]; char BootSiganture[2]; }; 

its size in memory is 520 bytes from me (although without alignment with the idea of ​​512). I use the following construction for reading:

 struct struct_fat16 table; if (-1 == fread(&table, sizeof(struct_fat16), 1, f)) { ... } 

but in this case, 520 bytes are read, not 512, and the data in the memory of the structure is also incorrectly placed. Therefore, the following question arises: is it possible to read data from a file and write it directly into the structure, that is, without using an intermediate buffer and copying each member:

 char tmp[512]; fread(&tmp, 512, 1, f)); memcpy(&table.Instruction, tmp, 3); ...//так для каждого члена структуры memcpy(&table.BootSignature, tmp, 3); 

How to calculate the size of the structure without alignment? Have to take the size of each of its members and summarize? Or do you have any other means?

    2 answers 2

     #pragma pack(1) struct struct_fat16 { char Instruction[3]; char IdOs[8]; uint16_t BytesPerSector; uint8_t SectorPerCluster; uint16_t ReservedSectors; uint8_t NubmerOfFATs; uint16_t RootEntries; uint16_t TotalSectors; uint8_t MediaDescriptor; uint16_t SectorPerFat; uint16_t SectorPerTrack; uint16_t Heads; uint32_t HiddenSectors; uint32_t BigTotalSectors; uint8_t PhysicalDiskNumber; uint8_t CurrentHead; uint8_t Signature; uint32_t VolumeSerialNumber; char VolumeLabel[11]; char SystemID[8]; char CodeBootLoader[448]; char BootSiganture[2]; }; #pragma pack(0) 

    And it will be exactly 512.

    • And what is the practical sense to disable the packaging structure? For the sake of a few bytes to lose word alignment? - pavel
    • @pavel, the practical meaning is stated in the question: the exact mapping of the structure of the structure to external data. - PinkTux
    • You misunderstood me a little. I meant when it can be used in a real (non-educational project), it became interesting to me. - pavel
    • 2
      @pavel, when working with any external data that has a certain structure. Starting with some banal BMP header, ending with binary protocols and data transfer between machines with different bitness. - PinkTux
    • @PinkTux And you can’t tell about the previous questions: How to calculate the size of the structure itself without taking into account the alignment? Have to take the size of each of its members and summarize? - rubeno4ka

    Perhaps it is worth transferring the structure field by field instead of reading a single piece? Then there is no need to fight with field alignment, and the processor itself will be happy with the aligned data.

     struct struct_fat16 table; fread(&table.fat16, sizeof(table.fat16), 1, f); fread(&table.IdOs, sizeof(table.IdOs), 1, f); // ... fread(&table.BootSiganture, sizeof(table.BootSiganture), 1, f); if(ferror() == 0) { // Работаем дальше } else // Обрабатываем ошибку чтения 
    • " and the processor itself will be happy with the leveled data " - and how happy will the programmer working with this hemorrhoids for a penny saving! Imagine, instead of a single read / write operation, he will have to perform a couple of dozen ... - PinkTux
    • @PinkTux, the programmer works once (when writing), and then the processor reads all this and executes, executes and writes, and so many, many times ... So the savings are not quite penny. By the way, one good man said that the machine should be lazy, not the programmer. - ߊߚߤߘ
    • "the programmer works once " - as already mentioned more than once, after that do not forget to hide from those who support this code. Ah, yes, it’s still good for Hindus, with line-by-line payment :) I don’t see any more advantages. At least until you show on profiler runs that, in each specific case, the benefit from leveling clearly exceeds the overhead of multiple calls, and the benefit from this savings exceeds the cost of maintaining the code. However, the owner is the master, my business is only to offer a solution to the problem. - PinkTux
    • @PinkTux, I do not argue, my decision is not the ultimate truth, but just a recommendation. As for the profiler, I agree, it is necessary to analyze each case separately in order to determine its profitability. - ߊߚߤߘ
    • one
      A person who has written a lot of similar low-level code. Never do that. Never. I want super-optimization - build your bikes (on a pure assembler, of course, and without any operating systems - this is not optimal!), I want a normal life - you need to use regular means of the language - Alexey Esaulenko