當指標遇上結構

Posted by: 邱小新 at 上午10:50 in ,

請注意下列二行程式碼有啥不同?

1. (__xdata unsigned char *)(icmp_data_rx+sizeof(struct icmp_hdr)) 2. ((__xdata unsigned char *)icmp_data_rx)+sizeof(struct icmp_hdr) 3. (__xdata unsigned char *)icmp_data_rx+sizeof(struct icmp_hdr)

沒錯,就是括弧位置不同,但是請看下列編譯出來的組合碼。

../source/icmp.c:54: (__xdata unsigned char *)(icmp_data_rx+sizeof(struct icmp_hdr)), mov dptr,#_icmp_data_rx movx a,@dptr mov r4,a inc dptr movx a,@dptr mov r5,a mov a,#0x40 ; 不同處 add a,r4 mov _memcpy_PARM_2,a clr a addc a,r5 ../source/icmp.c:54: ((__xdata unsigned char *)icmp_data_rx)+sizeof(struct icmp_hdr), mov dptr,#_icmp_data_rx movx a,@dptr mov r4,a inc dptr movx a,@dptr mov r5,a mov a,#0x08 ; 不同處 add a,r4 mov _memcpy_PARM_2,a clr a addc a,r5

注意到那不同處的地方了吧,二者算出來的值卻相差十萬八千里,其實在指標使用時,這是一個很容易犯錯的地方。當你原本只是要取一個結構結尾的指標,很自然的會寫出 1 的程式碼,但那是錯誤的。因為指標加法是根據指標的變數型態去相加,比如一個 short 指標加一,是指向下一個 short 位置,也就是指數加二。而在此案例上,第一種寫法是指向第8個結構的位置,也就 8x8=64=0x40 的位置,實在是大錯特錯。正確寫法為第2,3個寫法。

二的補數 (電腦負數表示法)

Posted by: 邱小新 at 下午4:26 in

二的補數法(2's complement)是電腦中為了儲存及運算有正負號的整數而使用的一種方法,要用二進位表達一個負整數的方法很多,但是二的補數表示法使得負整數與正整數的運算(加、減、及乘法)完全一致,不需要額外的硬體來處理。

範例

以 4 位元二的補數數字來說。例如:1 + (-2) = -1,0001(1) + 1110(-2) = 1111(-1)。你可以發現二的補數的加法只要使用標準的二進位加法就可以了。

2 進位無號整數有號整數
111115-1
111014-2
110113-3
110012-4
101111-5
101010-6
10019-7
10008-8
011177
011066
010155
010044
001133
001022
000111
000000

十進制轉成二進制

以 -3 為例。

  1. 11: 先把數字部分轉換成二進制。
  2. 0011: 依照 bit 數,補齊空缺。
  3. 1100: 使用1的補數,將1變0,0變1。
  4. 1101: 再把1的補數加上1,形成2的補數。

二進制轉成十進制

以 1101 為例。

  1. 1100: 2的補數減1,還原成1的補數。
  2. 0011: 1變0,0變1。
  3. 3: 二進制轉成十進制。
  4. -3: 數字前加上負號。

while (i--) or while (--i)

Posted by: 邱小新 at 下午4:39 in

while (i--)

mov r2,#0xC8 mov ar3, r2 dec r2 mov ar6, r2 mov a, r3

while (--i)

mov r2,#0xC8 dec r2 mov a, r2

結論

這樣結果很明顯吧,i-- 比 --i 多用了一個 r6 register,而且也多了二個指令,下次記得寫 while (--i)。

運算子優先順序

Posted by: 邱小新 at 下午2:42 in

最近在寫一段程式碼,剛好有去注意它編譯出來的assembly code,發現怎麼沒有預期出來的結果。結果發現卻是運算子優先順序的問題。切記位元運算的優先權為 shift > and > xor > or,之前一直以為三者是一樣大,原來卻不是如此。希望以前寫的產品不要因為如此而出問題啊,阿彌陀佛,善哉善哉。

原始錯誤程式碼 tmp = *(volatile unsigned char __xdata *)(0x8001) | 0x10 & ~0x08; mov dptr,#0x8001 movx a,@dptr mov r2,a orl ar2,#0x10 修改正確程式碼 tmp = (*(volatile unsigned char __xdata *)(0x8001) | 0x10) & ~0x08; mov dptr,#0x8001 movx a,@dptr mov r2,a mov a,#0x10 orl a,r2 anl a,#0xF7

運算子優先順序

優先
順序
評估順序運算子說明

15

由左至右

., [], ()

欄位存取、陣列索引、函式呼叫和運算式群組

14

由右至左

++, --, -, ~, !, delete, new, typeof, void

一元運算子、傳回資料型別、物件建立、未定義的值

13

由左至右

*, /, %

乘法、除法、modulo 除法

12

由左至右

+, -

加法和字串串連、減法

11

由左至右

<<, >>, >>>

位元移位

10

由左至右

<, <=, >, >=, instanceof

小於、小於或等於、大於、大於或等於、instanceof

9

由左至右

==, !=, ===, !==

等號比較、不等比較、嚴格等號比較和嚴格不等比較

8

由左至右

&

位元 AND

7

由左至右

^

位元 XOR

6

由左至右

|

位元 OR

5

由左至右

&&

邏輯 AND

4

由左至右

||

邏輯 OR

3

由右至左

?:

條件式

2

由右至左

=, OP=

指派、複合指派

1

由左至右

, (逗號)

多重評估