2017-04-12 89 views
0

我正在用C語言編程8051,使用Si Labs IDE。我目前有三個字節:address_byte3, address_byte2, and address_byte1。然後我初始化的變量address_sum是一個unsigned long int然後做就可以了以下操作...位移不正確?

address_sum=(address_byte3<<16)+(address_byte2<<8)+(address_byte1); 

此操作將導致我相信,值加載到address_sum如果address_byte3, address_byte2, & address_byte10x92, 0x56, & 0x78,分別是0xXX925678 。相反,我得到的值爲0xXX005678。我的邏輯聽起來很合理,但我又是編寫代碼的人,所以我有點偏見,可能被我自己的無知所矇蔽。有沒有人有解決方案或解釋爲什麼address_byte的價值是「失去」?

謝謝。

+2

你的系統上有多寬的int?它可能是16位。算術運算是通過將操作數提升爲'int'來完成的,所以用'16'移位會給你一個不錯的零... –

+1

@EugeneSh .:移動16會給你_undefined behavior_ –

+0

8051看起來是「Intel_MCS- 51「,它有8位寄存器? https://en.wikipedia.org/wiki/Intel_MCS-51 –

回答

1

當對它們進行計算時,比int短的變量被提升爲int。看起來你的類型是16位的,所以將它移動16位並不正確。

你應該明確地投下變量的結果類型(unsigned long):

address_sum = ((unsigned long)address_byte3<<16) + 
       ((unsigned long)address_byte2<<8) + 
       (unsigned long)address_byte1; 

最後鑄造是多餘的,但不痛。

+1

應注意字節實際上是'signed char' –

+0

這工作,並解決了我在我的代碼中看到的每一個其他錯誤。謝謝。我不知道我的'char'變量會被提升爲'int'。因此,在對它們進行按位操作時,投射它會阻止我失去任何一點點的東西?另外,我在例程中強制這樣做,這是否意味着這隻會在例程中發生,並且變量不會在'main()'中受到影響? –

+1

Casting不會影響鑄造變量。 –

1

16位int/unsigned的移位,以及@anatolyg的解釋只會導致16位答案。

我避免強制轉換,作爲一般的升級方案,有時它可能會因爲代碼隨着時間的推移而變化,並且維護者使用更寬的操作數。

備選方案:

((type_of_target) 1) *:這將確保各操作是至少目標的寬度。

unsigned long address_sum; 
... 
address_sum = (1UL*address_byte3<<16) + (1UL*address_byte2<<8) + address_byte1; 

分配到目的地,然後運行:

address_sum = address_byte3; 
address_sum = address_sum << 8 + address_byte2; 
address_sum = address_sum << 8 + address_byte1; 

手法高明,以爲不愉快的看1行的選擇。回想* +較高位次比轉向

address_sum = (0*address_sum + address_byte3 << 16) + 
       (0*address_sum + address_byte2 << 8) + address_byte1; 

考慮@Eugene Sh.關注,並採用8位無符號「字節」。

0

我的首選是chux上的變體

更大的聲明地址; 字節聲明a,b,c;

address =a; address<<=8; 
address|=b; address<<=8; 
address|=c; 

儘管是最詳細的答案,迄今爲止所有的答案應該優化成基本相同的代碼。但必須測試特定的編譯器才能看到。無論如何,8051可以每指令一次移動多位嗎?不記得了。

+0

是的,你可以每個指令移動多個位。我確信這就是你在上面的例子中所做的事情。我的問題是我沒有意識到我的變量被提升爲int,並且當我移動了16位時,最上面的變量丟失了,因此給我一個未定義的行爲。 –

+0

我說的是指令集,一些指令集的移位指令是一次一位,你必須多次調用指令。我經歷過這麼多的指令集,我不記得幾年來我沒有用過的每一個細節的細微差別...... 8051來自每個班次一位的時代,但8086是一個類似的時代,有一個多位轉換選項。 –

+0

是的,它使用每位指令(rlc或rrc基本上)一位移位,但由於寄存器是8位,移位實際上不會發生在這裏,寄存器可能不會被使用,但是三個存儲位置,我不知道你會使用24位地址,但這是另一回事...... –