Arithmetic Operators
+-*/%
Except the % operator, the other operators are applicable to both the floating point type and integer type.
When both operands of the/operator are integers, it performs the division operation. In other cases, it executes the division of floating point numbers. Any operator of the division operation is negative, and the calculation result is defined by the compiler. The "/" operator of the integer type is also an integer, truncating the decimal part
% Is the modulo operator. It accepts two integer operands and divides the left operand by the right operand. Its return value is the remainder instead of the quotient.
Avoid negative numbers involved in the/and % operations as much as possible. The result may be uncertain.
#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);}
Running result:
100 is divisible by 10
100 is divisible by 10
100 is divisible by 11
Logical operators
& |!
Use & | to evaluate the join expression from left to right. If the result is known, it is stopped immediately.
Note! And ~ Operator difference :! Is logical inversion ,~ Is bitwise Inversion
#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);}
Running result:
A = 2 x = 1
Bitwise operators
& | ^ ~ <>
& Can be used to block (mask off) bits, | can be used to set (turn on) bits
Value = value &~ (1 <
Value = value | 1 <
~ The operator can be used to define the full length of machine characters.
<Shifts n places left, equivalent to * 2 ^ n (without Overflow)
> Shifts n places to the right, equivalent to/2 ^ n
Both operands must be of the integer type.
The right shift operation has a problem that the Left shift operation does not face: when moving from the left to the new bit, you can choose two solutions:
One is logical shift, where the left-side slots are filled with 0;
The other is arithmetic shift. The bit moved to the left is determined by the sign bit of the original value. If the sign bit is 1, the bit moved to is 1, and the sign bit is 0, the bit moved to is 0, this ensures that the positive and negative forms of the original number remain unchanged.
Arithmetic shifts left are the same as logical shifts left. They are different only when the right shift is performed, and they are different only when the operand is negative.
Note: The standard description indicates that all the shift operations performed on the value of the unsigned type are logical shift operations, but whether logical shift or arithmetic shift is used for the signed value depends on the compiler. Therefore, if a program uses the right shift operation with a signed number, it cannot be transplanted.
& In specific circumstances, the remainder operation can be performed on behalf of %
When the divisor is 2 ^ n, the remainder can be used and replaced, and the efficiency is higher.
The following example shows how to judge the division.
Arbitrary Divisor
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; }
Divisor: 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; }
Extract, shift, and combine data to convert data in byte order.
#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);}
Running result:
0 XAABBCCDD
0 XDDCCBBAA
Common bitwise operators
#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))
Conversion
Type suffix
Int ??
Unsigned int u/U
Long l/L
Unsigned long ul/UL
Long ll
Unsigned long ull/ULL
Writing proper suffixes for constants can increase code readability and prevent Subtle problems caused by conversions.
#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 running result:
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 longint 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);}
Running result:
Ffff
Ffffffff
Ffffffff
Ffffffffffffff
The following two methods are used to define the full length of machine characters:
ULONG g_ulA = (ULONG)-1L
ULONG g_ulA = ~ 0UL
Integer increase (intergral promotion)
Some operators perform integer enhancement on the operands.
#include
int main(){ unsigned short usData = 0; if (~usData > (unsigned short)0) { printf ("TRUE\n"); } else { printf("FALSE\n"); }}
Running result:
FALSE
"~ "The operand will be upgraded to an integer type, and the USHORT will be upgraded to an INT type to a signed type. After the reverse operation, the four-byte full F (-1 <0)
Do not allow UCHAR or USHORT to directly perform "~", <> Similar problems exist.
Arithmetic type conversion
When the operation types of the operators are inconsistent, the Operation will convert the operation to the same type before the operation.
Principles:
1. type conversion to larger lengths due to different lengths
2. The length is the same and it is converted to the unsigned type.
Long double> float> unsigned long> unsigned int> int
Extension
Convert from a small data type to a large data type
To convert an unsigned number to a larger data type, simply add 0 at the beginning of the representation. This operation is called zero extension)
To convert a binary complement number to a larger data type, the rule is to execute a sign extension and add the highest valid bit value to the representation.
#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);}
Running result:
-12345 0xcfc7
53191 0xcfc7
-12345 0xffffcfc7
53191 0xcfc7