1, Original code, inverse code and complement code
1. Original code
The original code is the absolute value of the sign bit plus the true value, that is, the first bit represents the sign and the other bits represent the value
+1: 1* 2 ^0=1
Its original code is 00000000000000000001
-1: 1* 2 ^0=1
Its original code is 1000000000000001
2. Inverse code
The inverse of a positive number is itself
The inverse code of a negative number is based on its original code. The sign bits remain unchanged and the other bits are reversed.
+1: 00000000000000000000000000000001
-1: 11111111111111111111111111111110
3. Complement
The complement of a positive number is itself
The complement of a negative number is based on its original code. The sign bit remains unchanged, the other bits are reversed, and finally + 1. (i.e. + 1 on the basis of inverse code)
+1: 00000000000000000000000000000001
-1: 11111111111111111111111111111111
4. Special attention
The original code, inverse code and complement of positive numbers are the same.
The computer stores a complement.
2, Operator
1. Arithmetic operator
Arithmetic operators are symbols that complete basic arithmetic operations, which are used to process four operations.
+ | Addition operation |
---|---|
- | Subtraction operation |
* | Multiplication |
/ | Division operation |
% | Remainder operation |
be careful:
- %The two operands of the operator must be integers. Returns the remainder after division.
- For the / operator, if both operands are integers, perform integer division. As long as there are floating-point numbers, it is floating-point division.
#include<stdio.h> int main() { int a = 7 % 2; //Mold taking int b = 7 / 2; float c = 7 / 2.0; printf("%d\n", a); //1 printf("%d\n", b); //3 printf("%f\n", c); //3.500000 return 0; }
2. Shift operator
<< | Shift left operator |
---|---|
>> | Shift right operator |
be careful:
The shift left or shift right operator applies only to integers.
2.1 shift left operator
Shift rule: discard on the left and fill 0 on the right
#include<stdio.h> int main() { int num = 10; //num is an integer, accounting for four bytes, that is, 32 bit s int a = num << 1; //Shift left operator printf("a=%d\n", a); //20 return 0; }
Why is the value of a 20, not 100?
Because 1 * 2 ^ 3 + 1 * 2 ^ 1 = 10;
Therefore, the binary of 10 in memory is:
Complement: 0000000000000000000000001010
The result is: 1 * 2 ^ 4 + 1 * 2 ^ 2 = 20
2.2 shift right operator
Shift rule:
There are two kinds of shift right operations:
- Logical shift
Fill the left with 0 and discard the right - Arithmetic shift
The left is filled with the sign bit of the original value, and the right is discarded
warning ⚠ :
For shift operators, do not move negative digits.
For example:
int num = 10; num>>-1;//error
3. Bitwise operator
&/ / bitwise and (if the corresponding binary bit has 0, it is 0, and if both are 1 at the same time, it is 1)
|/ / by bit or (if the corresponding binary bit has 1, it is 1, and if the two bits are 0 at the same time, it is 0)
^/ / bitwise XOR (0 for the same, 1 for the different)
Note: their operands must be integers.
#include<stdio.h> int main() { int a=3; int b = -2; int c = a & b; printf("%d\n", c); //2 //%d - indicates that we want to print the value of c in signed form //Original code of 1000000000000010 - 2 //11111111111111111111111111111111111111111101 - 2 //11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110 - 2 //000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 //111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 //000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 //000000000000000000000000000000000000000000 10 bitwise and result (complement) //Because the sign bit of the result is 0, it is a positive number //The complement code is the original code 000000000000000000000000000000000000 10 //Therefore, the result is 1 * 2 ^ 1 = 2 return 0; }
3.1 expansion
a^a=0
0^a=a
XOR supports commutative law:
a ^ a ^ b = b
a ^ b ^ a = b
3.2 trial ox knife
·You cannot create a temporary variable (the third variable) to exchange two numbers.
#include <stdio.h> int main() { int a = 10; int b = 20; a = a ^ b; b = a ^ b; //b=(a^b)^b=a^(b^b)=a^0=a a = a ^ b; //a=(a^b)^a=(a^a)^b=0^b=b printf("a = %d b = %d\n", a, b); return 0; //The code is not readable and only applies to integers }
4. Assignment operator
4.1 direct assignment
int weight = 120;//weight weight = 89;//Assignment using assignment operator int a = 10; int x = 0; int y = 20; a = x = y+1;//Continuous assignment (try not to write this)
4.2 compound assignor
+= -= *= /=
%=> > = (a > > = 1, i.e. a = a > > 1)<<=
&= |= ^=
#include <stdio.h> int main() { int a = 13; a |= (1 << 1); printf("%d\n", a);//15 return 0; }
5. Monocular operator
5.1 introduction to monocular operators
Unary operator: as the name suggests, an operator with only one operand.
! | Logical reverse operation |
---|---|
- | negative |
+ | positive |
& | Get address |
sizeof | The type length of the operand in bytes |
~ | Bitwise negation of a number |
- - | Front, rear -- |
++ | Pre and post + + (a + + Post + +: use first and then + +) |
* | Indirect access operator (dereference operator) |
(type) | Cast type |
#include <stdio.h> int main() { int a = -10; int* p = NULL; printf("%d\n", !0);//1 printf("%d\n", !2);//0 a = -a; p = &a; printf("%d\n", sizeof(a));//4 printf("%d\n", sizeof(int));//4 printf("%d\n", sizeof a);//Is that all right? sure printf("%d\n", sizeof int);//Is that all right? may not return 0; }
! Introduction to logical anti operation
#include <stdio.h> int main() { int a = 10; if (a)//a hello for real { printf("Hello\n"); } if (!a)//a is false. Goodbye { printf("bye\n"); } return 0; }
~Introduction to bitwise inversion
#include <stdio.h> int main() { int a = 0; //00000000000000000000000000000000000000000000 complement //111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 //1000000000000001 original code printf("%d\n", ~a); //-1 }
++, -- Introduction
//++And -- operators //Pre + + and post++ #include <stdio.h> int main() { int a = 10; int x = ++a; //First + +, then use, that is, the value of the expression is the value after the self increment of a. x is 11. a = 10; int y = a++; //Use first and then + +, that is, the value of the expression is the original value of a. y is 10; printf("%d %d", x, y); return 0; }
5.2 difference between sizeof and strlen
sizeof is an operator, not a function. It calculates the memory size of a variable or type creation variable. The unit is bytes. It has nothing to do with what data is stored in memory
strlen is a library function used to calculate the length of a given string. It starts scanning from a certain location in memory until it encounters the first string terminator '\ 0', and then returns the counter value. (length does not include '\ 0')
#include<stdio.h> int main() { char arr[10] = "abc"; printf("%d\n", sizeof(arr));//10 printf("%d\n", strlen(arr));//3 return 0; }
Special attention!!!
#include<stdio.h> int main() { int a = 5; short s = 10; printf("%d\n", sizeof(s = a + 2));//2 //sizeof occurs at compile time, and this expression has disappeared at run time printf("%d\n", s);//10 return 0; }
The expression inside sizeof does not participate in the operation.
6. Relational operators
> | >= |
---|---|
< | <= |
!= Used to test "inequality" | ==Used to test equality |
#include <stdio.h> int main() { int a = (3 > 5); printf("%d\n", a);//0 return 0; }
6.1 warning
In the process of programming = = and = are written incorrectly, resulting in errors.
7. Logical operators
&&Logic and
||Logical or
be careful:
Distinguish logical and bitwise AND
Distinguish between logical or and bitwise OR
7.1 test questions
#include <stdio.h> int main() { int i = 0, a = 0, b = 2, c = 3, d = 4; i = a++ && ++b && d++; //i = a++||++b||d++; 1,3,3,4 printf(" a = %d\n b = %d\n c = %d\n d = %d\n", a, b, c, d); return 0; } //What is the result of the program output? 1,2,3,4
Why?
As long as there is a false expression in logic and operation, the result must be false, so the following expressions will not be operated.
Similarly, if a true expression occurs in logic or operation, the result must be true, so the following expression will not be evaluated.
#include <stdio.h> int main() { int i = 0, a = 1, b = 2, c = 3, d = 4; i = a++ && ++b && d++; //i = a++||++b||d++; 1,3,3,4 printf(" a = %d\n b = %d\n c = %d\n d = %d\n", a, b, c, d); return 0; } //What is the result of the program output? 2,3,3,5
8. Conditional operator (ternary operator)
exp1 ? exp2 : exp3
#include <stdio.h> int main() { int a = 3; int b = 5; int m = 0; m = ((a > b) ? (a):(b));//5 printf("%d\n", m); return 0; } //First judge whether the expression a > b is true or false. If it is true, then m=a; If false, then m=b.
2, Comma expression
exp1 , exp2 , exp3 , ... expN
Comma expressions are multiple expressions separated by commas.
Comma expression, executed from left to right. The result of the entire expression is the result of the last expression.
#include<stdio.h> int main() { int a = 1; int b = 2; int c = (a > b, a = b + 10, a, b = a + 1);//comma expression printf("%d\n", c); return 0; }
if (a =b + 1, c=a / 2, d > 0) a = get_val(); count_val(a); while (a > 0) { //Business processing a = get_val(); count_val(a); } If you use a comma expression, override: while (a = get_val(), count_val(a), a>0) { //Business processing }
3, Expression evaluation
The order in which expressions are evaluated is partly determined by the priority and associativity of operators.
Similarly, the operands of some expressions may need to be converted to other types during evaluation. (to be explained later)
4, Properties of the operator
There are three factors that affect the evaluation of complex expressions.
- operator precedence
- Associativity of operators
- Control evaluation order
Which of the two adjacent operators should be executed first? Depends on their priorities. If the two have the same priority, it depends on their combination.
1. Operator priority (from high to low)
Operator | describe | Usage example | Result type | Associativity | Control evaluation order |
---|---|---|---|---|---|
() | Aggregation group | (expression) | Same as expression | N/A | no |
() | function call | rexp(rexp,...,rexp) | rexp | L-R | no |
[ ] | Subscript reference | rexp[rexp] | lexp | L-R | no |
. | Access structure members | lexp.member_name | lexp | L-R | no |
-> | Access structure pointer member | rexp->member_name | lexp | L-R | no |
++ | Suffix self increment | lexp ++ | rexp | L-R | no |
– | Suffix subtraction | lexp – | rexp | L-R | no |
! | Logical inversion | ! rexp | rexp | R-L | no |
~ | Bitwise inversion | ~ rexp | rexp | R-L | no |
+ | Monocular, indicating positive value | + rexp | rexp | R-L | no |
- | Monocular, indicating negative value | - rexp | rexp | R-L | no |
++ | Prefix self increment | ++ lexp | rexp | R-L | no |
– | Prefix subtraction | – lexp | rexp | R-L | no |
* | Indirect access | * rexp | lexp | R-L | no |
& | Get address | & lexp | rexp | R-L | no |
sizeof | Take its length, expressed in bytes | Sizeof rexp sizeof (type) | rexp | R-L | no |
(type) | Type conversion | (type) rexp | rexp | R-L | no |
* | multiplication | rexp * rexp | rexp | L-R | no |
/ | division | rexp / rexp | rexp | L-R | no |
% | Integer remainder | rexp % rexp | rexp | L-R | no |
+ | addition | rexp + rexp | rexp | L-R | no |
- | subtraction | rexp - rexp | rexp | L-R | no |
<< | Left shift | rexp << rexp | rexp | L-R | no |
>> | Right shift | rexp >> rexp | rexp | L-R | no |
> | greater than | rexp > rexp | rexp | L-R | no |
>= | Greater than or equal to | rexp >= rexp | rexp | L-R | no |
< | less than | rexp < rexp | rexp | L-R | no |
<= | Less than or equal to | rexp <= rexp | rexp | L-R | no |
== | be equal to | rexp == rexp | rexp | L-R | no |
!= | Not equal to | rexp != rexp | rexp | L-R | no |
& | Bit and | rexp & rexp | rexp | L-R | no |
^ | Bit exclusive or | rexp ^ rexp | rexp | L-R | no |
| | Bit or | rexp | rexp | rexp | L-R | no |
&& | Logic and | rexp && rexp | rexp | L-R | yes |
|| | Logical or | rexp || rexp | rexp | L-R | yes |
? : | Conditional Operator | rexp ? rexp : rexp | rexp | N/A | yes |
= | assignment | lexp = rexp | rexp | R-L | no |
+= | Add with | lexp += rexp | rexp | R-L | no |
-= | Subtract by | lexp -= rexp | rexp | R-L | no |
*= | Multiply by | lexp *= rexp | rexp | R-L | no |
/= | Divide by | lexp /= rexp | rexp | R-L | no |
%= | Take a mold with | lexp %= rexp | rexp | R-L | no |
<<= | Move left with | lexp <<= rexp | rexp | R-L | no |
>>= | Move right with | lexp >>= rexp | rexp | R-L | no |
&= | With | lexp &= rexp | rexp | R-L | no |
^= | With... XOR | lexp ^= rexp | rexp | R-L | no |
|= | In... Or | lexp |= rexp | rexp | R-L | no |
, | comma | rexp,rexp | rexp | L-R | yes |
2. Associativity of operators
L-R from left to right
R-L from right to left
N/A non binding
3. Control evaluation sequence
For example: | logic and: if the first expression is false, the following expression does not need to be evaluated, and the result must be false.
4. Some problem expressions
(1)
//The evaluation part of the expression is determined by the priority of the operator. //Expression 1 a*b + c*d + e*f
Note: Code 1 can only ensure that the calculation is earlier than + due to its higher priority than + during calculation, but the priority does not determine that the third * is executed earlier than the first +.
ab
cd
ab + cd
ef
ab + cd + ef
Or:
ab
cd
ef
ab + cd
ab + cd + ef
(2)
//Expression 2 c + --c;
Note: as above, the priority of the operator can only determine whether the operation of self subtraction - precedes the operation of + but we have no way to know whether the left operand c of the + operator is evaluated before or after the right operand, so the result is unpredictable and ambiguous.
(3)
//Code 3 - illegal expression int main() { int i = 10; i = i-- - --i * ( i = -3 ) * i++ + ++i; printf("i = %d\n", i); return 0; }
Test result of expression 3 in different compilers: result of illegal expression program:
value | compiler |
---|---|
-128 | Tandy 6000 Xenix 3.2 |
-95 | Think C 5.02(Macintosh) |
-86 | IBM PowerPC AIX 3.2.5 |
-85 | Sun SPARC CC (K & C compiler) |
-63 | gcc,HP_UX 9.0,Power C 2.0.0 |
4 | Sun SPARC ACC (K & C compiler) |
21 | Turbo C/C++ 4.5 |
22 | FreeBSD 2.1 R |
30 | Dec Alpha OSF1 2.0 |
36 | Dec VAX/VMS |
42 | Microsoft C 5.1 |
(4)
//Code 4 int fun() { static int count = 1; return ++count; } int main() { int answer; answer = fun() - fun() * fun(); printf( "%d\n", answer);//How much output? return 0; }
Is there a real problem with this code?
something the matter!
Although the results are the same on most compilers.
However, the above code answer = fun() - fun() * fun(); In, we can only know from the priority of operators: multiply first and then subtract.
The call order of functions cannot be determined by the priority of operators.
(5)
//Code 5 #include <stdio.h> int main() { int i = 1; int ret = (++i) + (++i) + (++i); printf("%d\n", ret); printf("%d\n", i); return 0; } //Try to execute gcc compiler in linux environment and VS2013 environment. See the results.
Look at the same code that produces different results. Why?
Simply look at the assembly code, you can analyze it clearly.
When the first + in this code is executed, whether the third + + is executed or not is uncertain, because depending on the priority and associativity of operators, the order of the first + and the third preceding + + cannot be determined.
Conclusion:
If the expression we write cannot determine the unique calculation path through the properties of the operator, there is a problem with this expression.
If you have any questions, you are welcome to criticize and correct!