Search
FILE *fopen(const char *path, const char *mode); size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream); size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream); int fclose( FILE *stream );
book.h
#ifndef __BOOK_H__ #define __BOOK_H__ #include <stdio.h> #define MAX_NAME_SIZE 19 struct Book { int year; char title[MAX_NAME_SIZE]; char* abstract; }; typedef struct Book Book; struct BookList { Book** books; size_t size; }; typedef struct BookList BookList; Book* create_book(int year, const char* title, const char* abstract); void destroy_book(Book* b); void print_book(Book* b); BookList* create_book_list(); void destroy_book_list(BookList* bl); void add_book(BookList* bl, Book* b); void print_book_list(BookList* bl); #endif
book.c
#include <stdio.h> #include <stdlib.h> #include <string.h> #include "book.h" Book* create_book(int year, const char* title, const char* abstract) { Book* p = (Book*)malloc(sizeof(Book)); if (p == NULL) { printf("Error: malloc failed in create_book\n"); return NULL; } p->year = year; for (size_t i = 0; i < MAX_NAME_SIZE; i++) { p->title[i] = '\0'; // erase "dangerous" leftover data } for (size_t i = 0; i < MAX_NAME_SIZE-1; i++) { p->title[i] = title[i]; if (title[i] == '\0') { break; } } if (abstract == NULL) { p->abstract = NULL; } else { p->abstract = (char*)malloc(strlen(abstract) + 1); if (p->abstract == NULL) { printf("Error: malloc abstract failed in create_book\n"); free(p); return NULL; } strcpy(p->abstract, abstract); } return p; } void destroy_book(Book* p) { free(p->abstract); free(p); } void print_book(Book* p) { printf("Title: %s, Publication year: %d, Abstract: %s\n", p->title, p->year, p->abstract); } BookList* create_book_list() { BookList* pl = (BookList*)malloc(sizeof(BookList)); if (pl == NULL) { printf("Error: malloc failed in create_book_list\n"); return NULL; } pl->books = NULL; pl->size = 0; return pl; } void add_book(BookList* pl, Book* p) { Book** people_ = (Book**) realloc(pl->books, (pl->size + 1) * sizeof(Book*)); if (people_ == NULL) { printf("Warning: Adding failed, no modification is being done.\n"); return; } pl->books = people_; (pl->books)[pl->size] = p; pl->size++; } void destroy_book_list(BookList* pl) { for (size_t i = 0; i < pl->size; i++) { destroy_book(pl->books[i]); pl->books[i] = NULL; } free(pl->books); free(pl); } void print_book_list(BookList* pl) { for (size_t i = 0; i < pl->size; i++) { printf("Book %zu:\n", i); print_book(pl->books[i]); } }
main.c
#include <stdio.h> #include <stdlib.h> #include <string.h> #include "book.h" BookList* get_example_list(); void test_list_contents(); int main() { test_list_contents(); return 0; } BookList* get_example_list() { BookList* pl = create_book_list(); Book* p1 = create_book(2005, "Programming in C", "Programming in C will teach you how to write programs in the C programming language."); Book* p2 = create_book(161, "Meditations", NULL); Book* p3 = create_book(-1500, "Poor Man of Nipur", ""); add_book(pl, p1); add_book(pl, p2); add_book(pl, p3); return pl; } void test_list_contents() { BookList* pl = get_example_list(); print_book_list(pl); destroy_book_list(pl); }
run
$ gcc -Wall -pedantic -O3 -g main.c book.c -o app $ ./app Book 0: Title: Programming in C, Publication year: 2005, Abstract: Programming in C will teach you how to write programs in the C programming language. Book 1: Title: Meditations, Publication year: 161, Abstract: (null) Book 2: Title: Poor Man of Nipur, Publication year: -1500, Abstract:
Poskytnutá knihovna pracuje s kolekcí struktur Book, která uchovává informace o jednotlivých svazcích. Naším úkolem je tuto kolekci uložit do (a načíst z) binárního souboru. Z paměťového hlediska chceme překopírovat bajty rozmístěné v operační paměti do sekvence (stream) bajtů reprezentované FILE.
Book
hexdump -C
BookList *pl = get_example_list(); Book *p = pl->books[0]; fwrite(p, sizeof(Book), 1, f);
.title
.abstract
.year
Použijte nově nabité znalosti k implementaci knihovny:
book_serializer.h
#ifndef __BOOK_SERIALIZER_H__ #define __BOOK_SERIALIZER_H__ #include <stdio.h> #include "book.h" void serialize_book(FILE* f, Book* p); Book* deserialize_book(FILE* f); void serialize_book_list(FILE* f, BookList* pl); BookList* deserialize_book_list(FILE* f); #endif
.abstract=“”
.abstract=NULL
serialize_book
deserialize_book
test_list_contents()
serialize_book_list
deserialize_book_list
V Structure Layout se dočteme, že rozložení dat ve struktuře závisí na lokální platformě (typicky na HW architektuře (např. x86-64) a operačním systému). Ve struktuře mohou být vloženy úseky nevyužitého místa (padding), které zajistí, že jednotlivé prvky se nachází na tzv. zarovnaných adresách (dělitelných specifickou konstantou). Lišit se také může lišit pořadí bytů celočíselných hodnot (tzv, endianita).
Pokud budeme přesouvat data mezi různými platformami, musíme se “dohodnout” na společné reprezentaci, se kterou budou seznámeny obě strany. Pro komunikaci přes síť (např. v IP) bylo bajtové pořadí má být big-endian (tedy platforma která přijímá data ze sítě očekává big-endian). Počítače v laboratoři naopak používají little endian (tedy obrácené pořadí).
le_to_be
stdint.h
uint32_t le_to_be(uint32_t v);
uint32_t host_to_net32(uint32_t v)
uint32_t htonl(uint32_t hostlong);
float