簡體   English   中英

如何通過數組索引修改 C 結構?

[英]How can I modify a C struct by an array index?

我正在制作的游戲中使用結構,該結構包含有關人形機器人的信息(位置、速度等)。 我有一個用於播放器的結構和一個用於僵屍的結構。 我將僵屍結構添加到一個數組中(並計划對其他敵人做同樣的事情),以便在每個幀循環中迭代它們並將它們向前推進一步或解決游戲邏輯。 (作為記錄,該游戲在 Nintendo DS 上運行)。 不幸的是,我似乎無法通過數組索引修改結構的值,因為值不會改變。 直接修改結構是可行的,但是獨立更新每個結構將是一個巨大的痛苦(循環遍歷結構數組的原因)。 這是更深入的代碼:

typedef struct{
    int x;
    float y;
    float speed;
    bool isSwordActive;
    bool facingRight;
} humanoid;

void game(){
    humanoid player = {12, 12, 0, false, false};
    humanoid zombie = {226, 12, 0, false, false};
    humanoid objects[1] = {zombie};

    while(1){
        // This works
        zombie.y += zombie.speed;
        zombie.speed += 0.125;

        // This does not work
        for(int i = 0; i < sizeof(objects)/sizeof(objects[0]); i++){
            objects[i].y += objects[i].speed;
            objects[i].speed += 0.125;
        }
    }
}

有人可以解釋為什么這不起作用,以及可能的解決方案嗎? 謝謝!

objects應該是一個指針數組。 您正在將數據復制到數組中,因此原始對象未受影響。

這是重構的代碼。 注釋如下:

#define bool int
#define false 0
#define true 1

typedef struct {
    int x;
    float y;
    float speed;
    bool isSwordActive;
    bool facingRight;
} humanoid;

void
game()
{
    humanoid player = { 12, 12, 0, false, false };
    humanoid zombie = { 226, 12, 0, false, false };

// ORIGINAL
#if 0
    humanoid objects[1] = { zombie };
// FIXED
#else
    humanoid *objects[2] = { &zombie, &player };
#endif

// ORIGINAL
#if 0
    while (1) {
        // This works
        zombie.y += zombie.speed;
        zombie.speed += 0.125;

        // This does not work
        for (int i = 0; i < sizeof(objects) / sizeof(objects[0]); i++) {
            objects[i].y += objects[i].speed;
            objects[i].speed += 0.125;
        }
    }
#endif

// BETTER
#if 0
    while (1) {
        // This works
        zombie.y += zombie.speed;
        zombie.speed += 0.125;

        // This does not work
        for (int i = 0; i < sizeof(objects) / sizeof(objects[0]); i++) {
            objects[i]->y += objects[i]->speed;
            objects[i]->speed += 0.125;
        }
    }
#endif

// BEST
#if 1
    while (1) {
        // This works
        zombie.y += zombie.speed;
        zombie.speed += 0.125;

        // This does not work
        for (int i = 0; i < sizeof(objects) / sizeof(objects[0]); i++) {
            humanoid *obj = objects[i];
            obj->y += obj->speed;
            obj->speed += 0.125;
        }
    }
#endif
}

在上面的代碼中,我使用cpp條件來表示舊代碼和新代碼:

#if 0
// old code
#else
// new code
#endif

#if 1
// new code
#endif

這行得通,謝謝! 指針總是把我搞砸了。 如果你不介意,你能解釋為什么最好的解決方案比更好的解決方案更好嗎? 是性能方面的嗎? 如果對象太多並為每個對象創建新變量,性能會不會降低一點? 謝謝! – 胡安R4140

我們不是在創建/復制數組元素的內容(例如 20 個字節)。 我們只是在計算數組元素的地址 無論如何都必須這樣做,所以沒有額外的代碼。

這是一個根本的區別,我認為這對你來說仍然是一個困惑點。

如果我們在沒有優化的情況下編譯,“更好”的解決方案將重新評估objects[i]三次 在它可以“使用” object[i]之前,必須獲取那里的值並將其放入 CPU 寄存器中。 也就是說,它會這樣做:

regA = &objects[0];
regA += i * sizeof(humanoid);
regA = *regA;
regA->something

同樣,這重復了 3 次:

regA = &objects[0];
regA += i * sizeof(humanoid);
regA = *regA;
regA->something
regA = &objects[0];
regA += i * sizeof(humanoid);
regA = *regA;
regA->something
regA = &objects[0];
regA += i * sizeof(humanoid);
regA = *regA;
regA->something

如果我們進行優化編譯,生成的代碼將類似於“最佳”解決方案。 也就是說,編譯器意識到objects[i]在給定的循環迭代中是不變的,所以它只需要計算一次:

regA = &objects[0];
regA += i * sizeof(humanoid);
regA = *regA;
regA->something
regA->something
regA->something

請注意,編譯器必須始終將計算出的地址值放入寄存器中,然后才能使用它。 編譯器將假定obj應該在寄存器中。 因此,不會生成額外的代碼。

在“最佳”版本中,我“告訴”編譯器如何生成高效代碼。 而且,它會在沒有優化的情況下生成高效的代碼。

而且,在幾個不同的地方做obj->something比在多個地方做objects[i]->something更容易閱讀[由“類人”程序員;-)]。

這將通過 2D 數組更加顯示其價值。

暫無
暫無

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

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