算術運算符
+ - * / %
除了%操作符,其余幾個操作符都是既適用於浮點類型有適用於整數類型。
當/操作符的兩個操作數都是整數時,它執行整除運算,在其他情況下則執行浮點數除法,整除運算的任意操作符為負值,運算結果又編譯器定義。整數類型進行 "/" 運算商也是整數,截斷小數部分
%為取模操作符,它接受兩個整型操作數,把左操作數除以右操作數,它的返回值是余數而不是商
應盡量避免讓負數參與/ 和 %運算,結果肯能是不確定的
#include運行結果:void div(unsigned int i, unsigned int j) { if (i == ((i/j)*j)) { printf ("%u is divisible by %u\n", i, j); } } void div_mod(unsigned int i, unsigned j) { if (i == (((i/j)*j) + i%j)) { printf ("%u is divisible by %u\n", i, j); } } int main() { div(100, 10); div(100, 11); div_mod(100, 10); div_mod(100, 11); }
100 is divisible by 10
100 is divisible by 10
100 is divisible by 11
邏輯操作符
&& || !
使用&&或||連接的表達式從左到右求值,已知結果則立即停止。
注意!與~操作符的區別:!是邏輯取反,~是按位取反
#include運行結果:int main() { int a; int i; for (a=0, i=0; a<=1&&!i++; a++) { a++; } printf("a = %d x = %d\n", a, i); }
a = 2 x = 1
位操作符
& | ^ ~ << >>
&可用於屏蔽(mask off)位,|可用於設置(turn on)位
value = value & ~(1< value = value | 1< ~操作符可用於定義機器字長全F << 左移n位,等效於 *2^n(不溢出情況下) >> 右移n位,等效於/ 2^n 左移右移兩個操作數必須都是整型類型 右移位操作存在一個左移位操作不曾面臨的問題:從左邊移入新位時,可以選擇兩種方案: 一種是邏輯移位,左邊移入的位用0填充; 另一種是算術移位,左邊移入的位有原先該值的符號位決定,符號位為1則移入的位均為1,符號位為0則移入的位均為0,這樣能夠保證原數的正負形式不變。 算術左移和邏輯左移是相同的,它們只在右移時不同,而且只有當操作數是負值時才不一樣。 注:標准說明無符號類型值的執行的所有移位操作都是邏輯移位,但對於有符號值,到底是采用邏輯移位還是算術移位取決於編譯器。因此,一個程序如果使用了有符號數的右移位操作,它就是不可移植的。 &在特定情況下可以代替%進行取余運算 除數為2^n時取余可用&代替,且效率更高 以下為判斷整除的例子 除數任意 0XAABBCCDD 位運算符常見用法 轉換 類型 後綴 int ?? unsigned int u/U long l/L unsigned long ul/UL long long ll unsigned long long ull/ULL 為常量寫適當的後綴,可增加代碼可讀性,也能預防由於轉換引起的微妙問題 the default size 4 運行結果: ffff ULONG g_ulA = (ULONG)-1L ULONG g_ulA = ~0UL 整型提升(intergral promotion) 某些運算符會對操作數進行整型提升 FALSE "~"會對操作數做“整型提升”,USHORT 提升為INT變為有符號類型,取反後為四字節全F(-1<0) 不要讓UCHAR , USHORT,直接進行“~”, << >>也有類似問題 當運算符的操作數類型不一致時,運算前會將操作數轉換為同一類型 原則: 1、長度不同,往更大長度的類型轉換 2、長度相同,往無符號類型轉換 long double > double > float > unsigned long > long > unsigned int > int 擴展 從一個較小的數據類型轉換到一個較大的類型 要將一個無符號數轉換為一個更大的數據類型,只要簡單地在表示的開頭添加0。這種運算被稱為零擴展(zero extension) 要將一個二進制補碼數字轉換為一個更大的數據類型,規則是執行一個符號擴展(sign extension),在表示中添加最高有效位的值。 -12345 0xcfc7BOOL_T IsDivisible_A(IN UINT uiX, IN UINT uiY)
{
BOOL_T bDiv = BOOL_FALSE;
if (0 == (uiX%uiY))
{
bDiv = BOOL_TRUE;
}
return bDiv;
}
BOOL_T IsDivisible_B(IN UINT uiX, IN UINT uiY)
{
BOOL_T bDiv = BOOL_FALSE;
if (uiX == ((uiX/uiY)*uiY))
{
bDiv = BOOL_TRUE;
}
return bDiv;
}
除數為2^n
BOOL_T IsDivisible_8_A(IN UINT uiX)
{
BOOL_T bDiv = BOOL_FALSE;
if (0 == (uiX&0x7U))
{
bDiv = BOOL_TRUE;
}
return bDiv;
}
BOOL_T IsDivisible_8_B(IN UINT uiX)
{
BOOL_T bDiv = BOOL_FALSE;
if (uiX == ((uiX>> 3UL)<<3UL))
{
bDiv = BOOL_TRUE;
}
return bDiv;
}
對數據進行截取、移位、組合,就可以進行字節序轉換
#include
運行結果:
0XDDCCBBAA
#define BIT_SET(f, b) ((f) |= (b))
#define BIT_RESET(f, b) ((f) &= ~(b))
#define BIT_TEST(f, b) (((f)&(b)) != 0)
#define BIT_MATCH(f, b) (((f)&(b)) == (b))
typedef enum tagEvent
{
EVENT_X = 0,
EVENT_Y,
EVENT_Z
}
#define EVENT_MASK(enEvt) ((UINT)(1UL << (ULONG)(UINT)(enEvt)))
#define EVENT_ON(uiCur, enEvt) (BIT_SET(uiCur, EVENT_MASK(enEvt)))
#define EVENT_OFF(uiCur, enEvt) (BIT_RESET(uiCur, EVENT_MASK(enEvt)))
#define EVENT_TEST(uiCur, enEvt) (BIT_TEST(uiCur, EVENT_MASK(enEvt)))
#define BIT_SET(f, b) ((f) |= (b))
#define BIT_RESET(f, b) ((f) &= ~(b))
#define BIT_TEST(f, b) (((f)&(b)) != 0)
#define BIT_MATCH(f, b) (((f)&(b)) == (b))
#define STATUS_X 0x01U
#define STATUS_Y 0x02U
#define STATUS_Z 0x04U
#define STATUS_ALL (STATUS_X | STATUS_Y | STATUS_Z)
#define STATUS_ISVALID(uiStatus) (BIT_TEST(uiStatus, STATUS_ALL) && \
!BIT_TEST(uiStatus, ~STATUS_ALL))
#include
32bitCPU運行結果:
the postfix U size 4
the postfix L size 4
the postfix UL size 4
the postfix LL size 8
the postfix ULL size 8
#include
ffffffff
ffffffff
ffffffffffffffff
#include
運行結果:
算術類型轉換
#include
運行結果:
53191 0xcfc7
-12345 0xffffcfc7
53191 0xcfc7