我是 C 編程的新手。我想了解 DB 的結構,以獲得編程和 CS 的新經驗。所以我開始寫作,現在我在第三部分https://cstack.github.io/db_tutorial/parts/part3.html
問題:所以有一段代碼,其中寫入了結構欄位的 OFFSET
typedef struct {
uint32_t id;
char username[32];
char email[255];
} Row;
#define size_of_attribute(Struct, Attribute) sizeof(((Struct*)0)->Attribute)
const uint32_t ID_SIZE = size_of_attribute(Row, id);
const uint32_t USERNAME_SIZE = size_of_attribute(Row, username);
const uint32_t EMAIL_SIZE = size_of_attribute(Row, email);
const uint32_t ID_OFFSET = 0;
const uint32_t USERNAME_OFFSET = ID_OFFSET ID_SIZE;
const uint32_t EMAIL_OFFSET = USERNAME_OFFSET USERNAME_SIZE;
const uint32_t ROW_SIZE = ID_SIZE USERNAME_SIZE EMAIL_SIZE;
然后作者寫了序列化函式
void serialize_row(Row *source, void *destination){
memcpy(destination ID_OFFSET , &(source->id) , ID_SIZE );
memcpy(destination USERNAME_OFFSET, &(source->username),USERNAME_SIZE);
memcpy(destination EMAIL_OFFSET, &(source->email),EMAIL_SIZE);
return;
}
但我知道該結構不能連續保存在 RAM 中,因為編譯器試圖以 2 的冪的大小保存資料(不僅是編譯器)。無論如何,對于第一個元素它會起作用,因為第一個元素需要一次放置,但后續欄位不能一次放在第一個欄位之后(可以有空閑空間)。這意味著只有USERNAME_OFFSET或EMAIL_OFFSET不起作用。
請給我解釋一下。
我正在使用 Manjaro linux(OS)
gcc(編譯器)
gdb(除錯器)
uj5u.com熱心網友回復:
為了序列化/反序列化,您需要確保有足夠的空間(因此資料元素不會被彼此覆寫)并且讓 serialize() 和 deserialize() 函式就格式達成一致。對于您的示例,它可能是:
size_t serialize_row(Row *source, void *dest) {
return sprintf(dest, "(%s,%d,%s)", source->email, source->id, source->username);
}
int deserialize_row(void *source, Row *dest) {
int n;
n = sscanf(dest, "(%s,%d,%s)", source->email, &source->id, source->username);
return n == 3;
}
順序無關緊要,外部形式與內部形式無關,重要的是管理緩沖區和 io 大小。請注意,順便說一句,如果source->email或source->name包含 a ),它可能會使此失敗,因此需要一個更強大的示例。
uj5u.com熱心網友回復:
是的,沒錯,你是對的,你的懷疑是對的。不能保證 struct 成員是連續的,struct 成員之間可能存在填充并且代碼不處理。
特別是因為這個原因,存在offsetof宏https://en.cppreference.com/w/c/types/offsetof。
此外,const使用 another 的值初始化 aconst不是 C 語言的一部分,而是作為擴展支持。在 C 中,您必須重復它(或在擴展時使用宏)。
此外,您應該更喜歡使用size_t,而不是uint32_t來表示大小和索引。
const size_t ID_OFFSET = offsetof(Row, id);
const size_t USERNAME_OFFSET = offsetof(Row, username);
const size_t EMAIL_OFFSET = offsetof(Row, email);
const size_t ROW_SIZE = sizeof(Row);
編譯器尋求以 2 的冪的大小保存資料(不僅是編譯器)
嗯,它的大小并不總是 2,它與 對齊alignof(type),隨型別而異。所以char不需要任何調整,它可以在任何地方,但long通常對齊到4個位元組。您可能想閱讀http://www.catb.org/esr/structure-packing/。
uj5u.com熱心網友回復:
因為當你做序列化功能的時候,你將它如何保存在檔案或HEAP記憶體空間中并不重要。您使用每個欄位的源確切地址,并將其大小用作位元組數。當您執行反序列化功能時,它再次無關緊要,因為您只是連續地手動放置所有資料,并且編譯器(如果有必要)會在結構的末尾添加填充。
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/368914.html
下一篇:使用fgets時不會被列印出來
