2010-04-30 75 views
7

我最近正在研究這個平臺,其中一個遺留代碼庫發佈了大量「強制增加需要對齊到N」的警告,其中N是施放目標的大小。警告:施放需要對齊

struct Message 
{ 
    int32_t id; 
    int32_t type; 
    int8_t data[16]; 
}; 

int32_t GetMessageInt(const Message& m) 
{ 
    return *reinterpret_cast<int32_t*>(&data[0]); 
} 

希望這是顯而易見的是一個「真實」的實施將是一個有點複雜,但基本的一點是,我有數據從什麼地方來,我知道,它的排列(因爲我需要的id和類型進行對齊),但我得到的消息是演員陣容增加對齊,在這個例子中,爲4.

現在我知道我可以用編譯器的參數來壓制警告,而且我知道我可以將括號內的內容放在括號內,以便首先將void *忽略,但我並不真正想要通過需要這種操作的所有代碼(這是因爲我們加載了大量的dat關閉磁盤,並且數據以字符緩衝區的形式出現,以便我們可以輕鬆地進行指針提示),但任何人都可以給我關於此問題的其他想法嗎?我的意思是,對我來說,這似乎是一個非常重要和普遍的選擇,你不會想警告,如果實際存在錯誤的可能性,那麼壓制警告是無濟於事的。最後,不能讓編譯器知道所討論的對象是如何在結構中實際對齊的,所以它應該能夠不擔心該特定對象上的對齊,除非它碰到了一兩個字節?

+0

是否有某種編譯/包裝指令你的編譯器支持讓它知道結構是x字節對齊的? – 2010-04-30 01:33:49

+0

「這個平臺」,不要讓我們猜測。 – 2010-04-30 01:40:23

+0

@ Hans-我無法分享特定的平臺詳細信息。 @邁克爾 - 我可以四處走動,開始將事情標記爲對齊,我開始這樣做,但問題無處不在。問題不在於「我該如何修復它」,而是「爲什麼編譯器在獲得所有需要的信息時都非常關心」。例如。它並沒有警告我可能會取消引用其他成員未對齊... – 2010-04-30 01:53:56

回答

4

一個可能的替代方法可能是:

int32_t GetMessageInt(const Message& m) 
{ 
    int32_t value; 
    memcpy(&value, &(data[0]), sizeof(int32_t)); 
    return value; 
} 

對於x86架構,對齊不會管那麼多了,它更是一個性能問題,這並不是你所提供的代碼真正相關。對於其他體系結構(例如MIPS),未對齊的訪問會導致CPU異常。


OK,這裏是另一種選擇:

struct Message 
{ 
    int32_t id; 
    int32_t type; 
    union 
    { 
     int8_t data[16]; 
     int32_t data_as_int32[16 * sizeof(int8_t)/sizeof(int32_t)]; 
     // Others as required 
    }; 
}; 

int32_t GetMessageInt(const Message& m) 
{ 
    return m.data_as_int32[0]; 
} 

這裏有上述的變異包括從cpstubing06的建議:

template <size_t N> 
struct Message 
{ 
    int32_t id; 
    int32_t type; 
    union 
    { 
     int8_t data[N]; 
     int32_t data_as_int32[N * sizeof(int8_t)/sizeof(int32_t)]; 
     // Others as required 
    }; 
    static_assert((N * sizeof(int8_t) % sizeof(int32_t)) == 0, 
        "N is not a multiple of sizeof(int32_t)"); 
}; 

int32_t GetMessageInt(const Message<16>& m) 
{ 
    return m.data_as_int32[0]; 
} 


// Runtime size checks 
template <size_t N> 
void CheckSize() 
{ 
    assert(sizeof(Message<N>) == N * sizeof(int8_t) + 2 * sizeof(int32_t)); 
} 

void CheckSizes() 
{ 
    CheckSize<8>(); 
    CheckSize<16>(); 
    // Others as required 
} 
+0

是的 - 這是一個平臺,將觸發未對齊的讀取異常,除非我將該對象標記爲未對齊。我當然可以複製數據,但似乎過度;如果我從磁盤上讀取一個填充內存的文件,我只想說「這是這裏,這是在這裏,這是在這裏」,而不必爲了沒有實際收益而亂搞。 – 2010-04-30 01:55:38

+1

@ dash-tom-bang:當然,這取決於編譯器,但是你可能會得到'memcpy'代表未對齊(只要編譯器知道)'int32_t'讀取的價格。例如,GCC在這方面非常出色,即使您獲取地址,也可以將變量優化到寄存器中,前提是您不要將地址傳遞給非內聯代碼。 – 2010-04-30 02:26:46

+0

我不認爲如果你的編譯器有一個體面的'memcpy'內在的複製會產生巨大的差異。 – msandiford 2010-04-30 02:28:45