14.4 布爾表達式
14.4.1 范圍檢測
通常,布爾表達式被用來檢測某個數(shù)值是否在特定的范圍內。例如,在圖形窗口處理程序中,常使用布爾表達式判斷屏幕中一個點是否在當前活動窗口范圍內。
下面的程序使用結構體定義點坐標并計算坐標的當前位置。
bool PointInRect1(Point p, Rectangle *r)
{ return (p.x >= r->xmin && p.x < r->xmax &&
p.y >= r->ymin && p.y < r->ymax);
}
上面的功能函數(shù),被編譯為下面的指令序列。
PointInRect1
LDR a4,[a3,#0]
CMP a1,a4
BLT |L000034.J5.PointInRect1|
LDR a4,[a3,#4]
CMP a4,a1
BLE |L000034.J5.PointInRect1|
LDR a1,[a3,#8]
CMP a2,a1
BLT |L000034.J5.PointInRect1|
LDR a1,[a3,#&c]!
CMP a2,a1
MOVLT a1,#1
MOVLT pc,lr
|L000034.J5.PointInRect1|
MOV a1,#0
MOV pc,lr
但上面的代碼并不是最精簡的。編譯器對(x >= min && x < max)形式的布爾表達式的處理過程比較復雜。它將以(unsigned)(x-min) < (max-min)形式實現(xiàn)布爾操作。所有對于上面范圍判斷的代碼,建議將函數(shù)寫成如下形式。
bool PointInRect2(Point p, Rectangle *r)
{ return ((unsigned) (p.x - r->xmin) < r->xmax &&
(unsigned) (p.y - r->ymin) < r->ymax);
}
這樣編譯出的匯編指令序列如下所示。
PointInRect2
LDR a4,[a3,#0]
SUB a1,a1,a4
LDR a4,[a3,#4]
CMP a1,a4
LDRCC a1,[a3,#8]
SUBCC a1,a2,a1
LDRCC a2,[a3,#&c]!
CMPCC a1,a2
MOVCS a1,#0
MOVCC a1,#1
MOV pc,lr
14.4.2 和零的比較操作
比較指令(CMP)將設置程序狀態(tài)字的條件標志位。另外,基本的算術指令也可以設置條件標志位,如使用指令MOVS、ADDS等。如果程序中的算術指令的執(zhí)行目的是為了將計算結果和零比較,那么就可以直接使用帶標志擴展的基本算術指令。如下面的兩條語句:
ADD R0, R0, R1
CMP R0, #0
可以合并為一條帶符號擴展的加法指令:
ADDS R0, R0, R1
事實上,C語言中的和零相關的關系操作都可以利用狀態(tài)標志寄存器的N位和Z位。如:x < 0, x >= 0, x = 0, x != 0,和無符號操作x = 0, x != 0 (or x > 0)。
對于每一條C語言中的關系操作,匯編器都將產(chǎn)生一條比較指令。如果關系操作和零相關,則可以將產(chǎn)生的比較指令移除。
下面是C語言中的關系操作被編譯的例子。
C源文件如下所示。
int g(int x, int y)
{
if ((x + y) < 0)
return 1;
else
return 0;
}
編譯后的結果如下。
g
ADDS a1,a1,a2
MOVPL a1,#0
MOVMI a1,#1
MOV pc,lr
所以,在使用C語言編程時,關系操作最好轉換成和零相關的,這樣既可以減少代碼密度,也可以提高程序的執(zhí)行效率。
C語言中,沒有和程序狀態(tài)寄存器的C位和V位直接相關的指令,所以要在程序中檢測這些標志,只能使用內嵌匯編。但C編譯器支持無符號溢出操作,下面的例子顯示了在有溢出操作時,編譯器對程序的處理。
C源代碼如下所示。
int sum(int x, int y)
{
int res;
res = x + y;
if ((unsigned) res < (unsigned) x) /* 判斷進位標志是否進位 */
res++;
return res;
}
編譯的匯編文件如下所示。
sum
ADDS a2,a1,a2
ADC a2,a2,#0
MOV a1,a2
MOV pc,lr