簡體   English   中英

malloc 的這種使用會導致“可選”結構字段嗎?

[英]Could this use of malloc lead to an “optional” struct field?

我正在實現一個結構,我需要(在運行時)有一個可選字段。
所以我想到了這個:

//...
#include <stdlib.h>

struct test {
  int x;  // Must be
  int y;  // Optional (Must be the last field..(?))
};

int main(int argc, char **argv) {
    // With the optional field
    struct test *a = malloc(sizeof(*a));
    a->x = 11;
    a->y = 55;
    
    // Without the optional field
    struct test *b = malloc(sizeof(*b) - sizeof(int));
    b->x = 22;
    
    // ...
    
    free(a);
    free(b);
    return 0;
}

這段代碼可以按我的要求做嗎?
可能添加一個位字段來檢查是否有可選字段。

此外,如果建議的解決方案有效,如果這是針對多個項目(> 100000)的列表實施的,那么保存 memory 會更好嗎?

這段代碼可以按我的要求做嗎?

好吧,它可以,但你不能依賴它。 不要這樣做; 這不是編寫正確程序的方法。

當你寫b->x = 22; ,編譯器有權表現得好像在b處有一個完整的struct test 您可能會想,“我只是將 22 放入成員x的字節中”,但編譯器可能會使用“存儲 8 個字節”指令:

  • 考慮一些架構,其中 memory 被組織成八字節組。 總線只能讀取和寫入整個 8 字節塊。
  • 由於無法在硬件中寫入四個字節,因此將四個字節寫入 memory 需要讀取八個字節,在處理器寄存器中操作它們以在其中四個字節中插入所需的值,然后將八個字節寫回 memory。
  • 編譯器要優化b->x = 22; ,並且它知道y尚未設置,因此允許它具有任何值。 因此,編譯器不會使用低效的寫入四字節序列,而是生成一個八字節存儲,將 22 放入b->x並將 0 放入b->y

然后這會失敗,因為編譯器剛剛將 0 寫入 memory 可能正在用於其他用途,因為它不是您為b分配的空間的一部分。

“如果你對編譯器撒謊,它就會報仇雪恨。” — 亨利·斯賓塞

What you're attempting doesn't conform to the C standard because you're attempting to use an object of type struct test that doesn't have enough memory allocated for it, even though you're only accessing the fields for which memory was分配。 可能有效,但你不能依賴它。

可以做的是使用靈活的數組成員

struct test {
  int x;
  int y[];
};

在這樣的結構中, sizeof(struct test)不包括最后一個成員。 您可以通過為結構分配空間以及所需的最后一個成員的盡可能多的數組元素來使用這樣的結構。 例如:

struct test *b = malloc(sizeof(*b) + sizeof(int));
b->x = 1;
b->y[0] = 2;

您需要使用數組索引來訪問最后一個成員,但這是一種以符合標准的方式執行所需操作的方法。

然后,如果您不想要最后一個成員,請執行以下操作:

struct test *b = malloc(sizeof(*b));
b->x = 1;

我認為您提出的解決方案很危險。 使用兩種不同的結構:

struct test_x {
   int x;
};

struct test_xy {
  int x;
  int y;
};

要么有兩個 arrays 要么將 void * 與鑒別器(例如標記指針)一起存儲到其中一個。 另一個選項是對可選元素使用指針,但 sizeof(int *) 至少在我的盒子上與 sizeof(int) 相同,這樣只會使事情變大。

如果所有 y 成員都是可選的,請考慮列布局,或者您可以對數據進行排序,以便所有 xy 元素排在第一位:

struct test_column {
  int *x;
  int *y;
};

struct test_column t = {
  .x = malloc(100000 * sizeof(int)),
  .y = 0

它對您沒有幫助,但聯合是兩個結構共享 memory 的標准方式,因此每個元素的大小是 max(sizeof(test_xy), sizeof(test_x)) 而不是 sizeof(test_xy) + sizeof(test_x)。

最后,考慮壓縮,特別是如果您使用 test_column 格式。

我 state 我不是 C 方面的專家,但我正在研究它。
我正在實現一個結構,我需要(在運行時)有一個可選字段。
所以我想到了這個:

//...
#include <stdlib.h>

struct test {
  int x;  // Must be
  int y;  // Optional (Must be the last field..(?))
};

int main(int argc, char **argv) {
    // With the optional field
    struct test *a = malloc(sizeof(*a));
    a->x = 11;
    a->y = 55;
    
    // Without the optional field
    struct test *b = malloc(sizeof(*b) - sizeof(int));
    b->x = 22;
    
    // ...
    
    free(a);
    free(b);
    return 0;
}

這段代碼可以按我的要求做嗎?
可能添加一個位字段來檢查是否有可選字段...


此外,如果建議的解決方案有效,如果這是針對多個項目(> 100000)的列表實施的,那么保存 memory 會更好嗎?


謝謝大家,提前。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM