程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> 關於C語言 >> C語言運算符

C語言運算符

編輯:關於C語言

算術運算符

+ - * / %

除了%操作符,其余幾個操作符都是既適用於浮點類型有適用於整數類型。

當/操作符的兩個操作數都是整數時,它執行整除運算,在其他情況下則執行浮點數除法,整除運算的任意操作符為負值,運算結果又編譯器定義。整數類型進行 "/" 運算商也是整數,截斷小數部分

%為取模操作符,它接受兩個整型操作數,把左操作數除以右操作數,它的返回值是余數而不是商

應盡量避免讓負數參與/ 和 %運算,結果肯能是不確定的

#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時取余可用&代替,且效率更高

以下為判斷整除的例子

除數任意

BOOL_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 

#define Conversion_4Byte(x ,y) \
        y =     \
        ((x & 0xFF000000U) >> 24)| \
        ((x & 0x00FF0000U) >> 8) | \
        ((x & 0xFF00U)  << 8)  | \
        ((x & 0xFFU)    << 24)
int main()
{
        unsigned int x = 0xAABBCCDD;
        unsigned int y = 0;

        Conversion_4Byte(x, y);

        printf("%#X \n%#X\n", x, y);

}
運行結果:

0XAABBCCDD
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))

轉換

類型 後綴

int ??

unsigned int u/U

long l/L

unsigned long ul/UL

long long ll

unsigned long long ull/ULL

為常量寫適當的後綴,可增加代碼可讀性,也能預防由於轉換引起的微妙問題

#include 

int main()
{
        printf("the default size %d\n", sizeof(0));
        printf("the postfix U size %d\n", sizeof(0U));
        printf("the postfix L size %d\n", sizeof(0L));
        printf("the postfix UL size %d\n", sizeof(0UL));
        printf("the postfix LL size %d\n", sizeof(0LL));
        printf("the postfix ULL size %d\n", sizeof(0ULL));
}
32bitCPU運行結果:

the default size 4
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 
#define USHORT  unsigned int
#define UINT    unsigned int
#define ULONG   unsigned long
#define UINT64  unsigned long long
int main()
{
        USHORT usA = (USHORT)-1;
        UINT   uiB = (UINT)-1;
        ULONG  ulC = (ULONG)-1;
        UINT64 uiD = (UINT64)-1;

        printf("%hx\n%x\n%lx\n%llx\n", usA, uiB, ulC, uiD);
}

運行結果:

ffff
ffffffff
ffffffff
ffffffffffffffff

通過以下兩種方式定義機器字長全F

ULONG g_ulA = (ULONG)-1L

ULONG g_ulA = ~0UL

整型提升(intergral promotion)

某些運算符會對操作數進行整型提升

#include 
int main()
{
        unsigned short usData = 0;
        if (~usData > (unsigned short)0)
        {
                printf ("TRUE\n");
        }
        else
        {
                printf("FALSE\n");
        }
}
運行結果:

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),在表示中添加最高有效位的值。

#include 

int main()
{
        int val = -12345;
        short sx = val;
        unsigned short usx = sx;
        int x = sx;
        unsigned int ux = sx;

        printf("%10d %#10hx\n", sx, sx);
        printf("%10u %#10hx\n", usx, usx);
        printf("%10d %#10x\n", x, x);
        printf("%10u %#10x\n", usx, usx);
}
運行結果:

-12345 0xcfc7
53191 0xcfc7
-12345 0xffffcfc7
53191 0xcfc7

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved