2014-09-23 217 views
1

我必須讀出uint32_t變量的字節,並且我已經從我的一位同事那裏看到了這種 實現。我的問題是,如果該代碼示例的行爲在「幾乎所有」32位微控制器上是可靠的。是否可以在每個32位微控制器上工作,還是我所依賴的平臺特定行爲? P.S .:本例中不考慮系統的字節順序。在嵌入式系統上投射指針,通過指針投射在32位變量上的字節指針

uint8_t  byte0=0; 
uint8_t  byte1=0; 
uint8_t  byte2=0; 
uint8_t  byte3=0; 
uint8_t  *byte_pointer; //byte_pointer 
uint32_t *bridge_pointer;//pointer_bridge between 32bit and 8 bit variable 
uint32_t var=0x00010203; 

bridge_pointer=&var; //bridge_pointer point to var 
byte_pointer=(uint8_t *)(bridge_pointer); //let the byte_pointer point to bridge_pointer 

byte0=*(byte_pointer+0); //saves byte 0 
byte1=*(byte_pointer+1); //saves byte 1 
byte2=*(byte_pointer+2); //saves byte 2 
byte3=*(byte_pointer+3); //saves byte 3 

由於提前

+1

'byte0 = byte_pointer [0]'等會更優雅(相當於'*(byte_pointer + 0)')。另外我不認爲'bridge_pointer'是絕對必要的,您可以立即將'&var'強制轉換爲'uint8_t *'。 – Kninnug 2014-09-23 12:10:27

+1

您可能想了解[別名](http://en.wikipedia.org/wiki/Aliasing_%28computing%29)和[指針別名](http://en.wikipedia.org/wiki/Pointer_aliasing)。 – 2014-09-23 12:11:25

回答

3
byte0=*(byte_pointer+0); //saves byte 0 

這條線(和下面的那些)是違反嚴格混疊的。聲明爲uint32_t的對象通過uint8_t類型的左值進行訪問;應該使用unsigned char而不是uint8_t,因爲允許字符類型的左值訪問不同類型的對象(如果存在uint8_t,則儘管放寬了別名規則,它的行爲與unsigned char相同)。

unsigned char *byte_pointer = (unsigned char *)(bridge_pointer); 
uint8_t byte0 = *(byte_pointer+0); 
    // byte0 can still be uin8_t, the access to var is important for aliasing 

如在comment提到的,byte_pointer[0]相當於*(byte_pointer+0)和較爲常見。

通過此更改,代碼具有明確定義的行爲。 (並且是便攜式的,以具有uint32_tuint8_t實施方式中,雖然端序可導致不同的結果,如在問題指出。)

嚴格混疊的相關標準部件是6.5 P6/7。

+0

謝謝你的回答,它幫助我很好。其他答案也很有用,謝謝。 – chhegema 2014-09-23 12:55:07

+0

實際上,'uint8_t'的行爲與unsigned char完全一樣,因此不會破壞嚴格的別名。 [看到這個](http://stackoverflow.com/questions/12666146/can-uint8-t-be-a-non-character-type)。 – Lundin 2014-09-23 13:50:08

+0

@Lundin:IIRC海灣合作委員會郵件列表討論了一段時間之前,它被認爲是一個海灣合作委員會的錯誤,它不使用該別名信息,並可能會改變。我不確定目前的狀況。當我找到它時我會鏈接。 – mafso 2014-09-23 14:11:42

4

你應該聲明byte_pointerunsigned char*,那麼你的例子將工作,如果你接受不同的輸出在小端。這裏是一個解決方案,它不依賴於字節序

uint8_t byte0 = var; 
uint8_t byte1 = var>>8; 
uint8_t byte2 = var>>16; 
uint8_t byte3 = var>>24; 

byte0將成爲LSB

1

在實踐中,代碼是除了字節序問題,便於攜帶。通過uint8_t指針訪問uint32_t的一部分將始終在標準之外的現實世界中工作。

Whether uint8_t is considered a character type or not is debated,但這個討論只是在學術上有興趣。 (如果它被認爲是一種字符類型,它不會在標準6.5/7中使用破壞別名規則。)實際上,uint32_t將不包含任何填充位或其他標準允許的理論廢話。

爲了避免字節碼問題,我建議重新編寫代碼以使用位移,就像在@ mch的答案中進行了反向解析。

+0

「填充位或標準允許的其他此類理論廢話。」 - 它沒有。參看C11(n1520)7.20.1.1 p1/2。 '(u)intN_t'類型表現得非常「正常」:二進制補碼和無填充位。 – mafso 2014-09-23 16:17:16

+0

@mafso所以沒有理由uint8_t不會工作。 – Lundin 2014-09-24 06:59:49

+0

@Lundin:標準將允許一個實現使用32中的任何一個! (即大約2.63E + 35)的方式將uint32_t的位映射到四個連續的uint8_t值的位。在實踐中,兩種映射比其他任何映射都要普遍得多,並且在任何非設計實現中可能至多會出現兩種映射。 – supercat 2017-10-17 22:46:15