C language series - Section 5 - detailed explanation of operators

1. Operator classification

  1. arithmetic operator
  2. Shift operators
  3. Bitwise operators
  4. Assignment operator
  5. unary operator
  6. Relational operator
  7. Logical operator
  8. Conditional Operator
  9. comma expression
  10. Subscript references, function calls, and structure members

1.1 binary

Here is a supplementary introduction to binary

1 . First of all, it should be clear that all data is stored in computer memory in binary form

2 . There are three forms of binary representation of integers

  1. The first bit on the leftmost side of the original code is the sign bit. The sign bit of a positive number is represented by 0 and the sign bit of a negative number is represented by 1
  2. Complement (the complement of a positive number is the original code; the complement of a negative number is the sign bit unchanged, the other bits are reversed, and then + 1)
  3. Inverse code (the inverse code of positive number is the original code; the inverse code of negative number is that the sign bit remains unchanged, and all other bits are reversed by bit)

Such as integer 5
Binary representation:
Source code: 00000000000000000001
Complement: 00000000000000000001
Inverse code: 00000000000000000001
Such as integer - 5
Binary representation:
Source code: 1000000000000000 101
Complement: 111111111111111111111111111111111111111111011
Inverse code: 111111111111111111111111111111111010

be careful:

  1. Integer is stored in the form of complement binary
  2. But when calculating, it is based on the original code
  3. Negative case: original code + complement = - 1 (because the + 1 of complement is + 1 in the case of negative)

2. Arithmetic operator

1+
2-
3.
4 * multiplication
5 / Division
6% surplus

Supplement:

  1. In addition to the% operator, several other operators can act on integers and floating-point numbers.
  2. For the / operator, if both operands are integers, perform integer division. As long as there are floating-point numbers, it is floating-point division.
  3. %The two operands of the operator must be integers. Returns the remainder after division.

Section 4, 5 and 6 are enough
Arithmetic operator link

3. Shift operator

< < shift left operator
>>Shift right operator
Note: the operands of shift operators can only be integers.

3.1 shift left operator (that is, multiply by 2 to the power of m)

Shift rule:

Discard on the left and supplement 0 on the right

3.2 shift right operator (i.e. m-power divided by 2)

Note that 1 is 0 after shifting 1 bit to the right Because 1 / 2 = 0 (rounded)
-1 is still - 1 after shifting 1 bit to the right
Just remember these two special situations

Shift rule:
First, there are two kinds of shift right operations:

  1. Logical shift
    Fill the left with 0 and discard the right
  2. Arithmetic shift
    The left is filled with the sign bit of the original value, and the right is discarded

So how to judge which type of right shift is based on?
method:
As mentioned above, shift - 1 right one bit to output and see the result

If arithmetic or shift right -
If the result is 1, it is a logical shift to the right
As shown in the figure, my compiler shifts arithmetic right

But whether it is arithmetic right shift or logical right shift depends on the compiler

warning ⚠ :
For shift operators, do not move negative digits, which is not defined in the standard.
For example:

int num = 10;
num>>-1;//error

4. Bitwise operator

Bit operators are: all operate on (binary)

& //Bitwise AND
| //Bitwise OR
^ //Bitwise XOR
 Note: their operands must be integers.

Supplement:

a&b express a Bitwise AND b Binocular operator
&b  Indicates the address b  Is a monocular operator

Practice:

#include <stdio.h>
int main()
{
	int num1 = 1;
	int num2 = 2;
	num1& num2;
	num1 | num2;
	num1^ num2;
	return 0;
}

General examples of C language, question 7

A perverse interview question:

You cannot create a temporary variable (the third variable) to exchange two numbers

Go directly to the answer, read the answer and then look at the analysis. If you don't look at the answer, you really can't think of this
#include <stdio.h>
int main()
{
	int a = 10;
	int b = 20;
	a = a ^ b;
	b = a ^ b;
	a = a ^ b;
	printf("a = %d b = %d\n", a, b);
	return 0;
}

Method 2:
#include<stdio.h>
int main()
{
	int a = 2, b = 5;
	a = a + b;
	b = a - b;
	a = a - b;
	printf("%d %d", a, b);
	return 0;
}

Key to this question:

  1. a^a = 0
  2. a ^b^ a = b

General examples of C language, question 8

practice:

Write code to realize: find the number of 1 in the binary of an integer stored in memory

Reference code:
//Method 1
#include <stdio.h>
int main()
{
	int num = 10;
	int count = 0;//count
	while (num)
	{
		if (num % 2 == 1)
			count++;
		num = num / 2;
	}
	printf("Number of 1 in binary = %d\n", count);
	return 0;
}
//Is there a problem thinking about such an implementation?
//Method 2:
#include <stdio.h>
int main()
{
	int num = -1;
	int i = 0;
	int count = 0;//count
	for (i = 0; i < 32; i++)
	{
		if (num & (1 << i))
			count++;
	}
	printf("Number of 1 in binary = %d\n", count);
	return 0;
}
//Think about whether it can be more optimized. Here we must cycle 32 times.
//Method 3:
#include <stdio.h>
int main()
{
	int num = -1;
	int i = 0;
	int count = 0;//count
	while (num)
	{
		count++;
		num = num & (num - 1);
	}
	printf("Number of 1 in binary = %d\n", count);
	return 0;
}
//Is this a good way? The optimization effect is achieved, but it is difficult to think of.

5. Assignment operator

The assignment operator is a great operator that allows you to get a value you were not satisfied with before. That is, you can reassign yourself.

int weight = 120;//weight
weight = 89;//Assign value if you are not satisfied
double salary = 10000.0;
salary = 20000.0;//Assign values using the assignment operator.
Assignment operators can be used continuously, such as:
int a = 10;
int x = 0;
int y = 20; a = x = y + 1;//continuous assignment 
How does this code feel?
The same semantics, you see:
x = y + 1; a = x;
Is this writing more clear, crisp and easy to debug.

In addition, how to assign a value to a string?

char a[20];
a = 'abc';error
 String cannot be used as assignment symbol(=)of
 But with strcpy(a,"abc")

Compound assignor

+=
-=
*=
/=
%=
>>=
<<=
&=
|=
^=

These operators can be written as compound effects.
such as

int x = 10; x = x+10; x += 10;//Compound Assignment 
//The same is true for other operators. This is more concise.

6. Monocular operator

6.1 introduction to monocular operators

! Logical reverse operation
-Negative value
+Positive value
&Take address
Type length of sizeof operand in bytes
~The binary bit negation of a number
– front, rear –
++Front and rear++
*Indirect access operator (dereference operator) (type) cast

Demo code:

#include <stdio.h>
int main()
{
	int a = -10;
	int* p = NULL;
	printf("%d\n", !2);
	printf("%d\n", !0);
	a = -a;
	p = &a;
	printf("%d\n", sizeof(a));
	printf("%d\n", sizeof(int));
	printf("%d\n", sizeof a);//Is that all right?
	printf("%d\n", sizeof int);//Is that all right?
	return 0;
}

In fact, we have seen about sizeof before. We can find the space occupied by variables (types).
Add:

The expression in sizeof() does not participate in the evaluation

6.2 sizeof and array

#include <stdio.h>
void test1(int arr[])
{
	printf("%d\n", sizeof(arr));//(2)
}
void test2(char ch[])
{
	printf("%d\n", sizeof(ch));//(4)
}
int main()
{
	int arr[10] = { 0 };
	char ch[10] = { 0 };
	printf("%d\n", sizeof(arr));//(1)
	printf("%d\n", sizeof(ch));//(3)
	test1(arr);
	test2(ch);
	return 0;
}
Q:
(1),(2)How much is the output of the two places? 
1 Output 40; 2 output 4
(3),(4)How much is the output of the two places?
(3)Output 10 (4)

because char ch[]Equivalent to a pointer. The size of the pointer depends on the type of computer
×32 The computer pointer type size is 4
×64 The computer pointer type size is 8

6.3 + + operators and -- operators

//++And -- operators
//Pre + + and--
#include <stdio.h>
int main()
{
	int a = 10;
	int x = ++a;
	/*First increment a, and then use a, that is, the value of the expression is a
	Value after self increment. x is 11.*/
	int y = --a;
	//First, self subtract a, and then use a, that is, the value of the expression is a
	The value after subtraction. y For 10;
	return 0;
}
//Post + + and--
#include <stdio.h>
int main()
{
	int a = 10;
	int x = a++;
	//Use a first and then increase it, so that the value of x is 10; Then a becomes 11;
	int y = a--;
	//First use a and then subtract from it, so that the value of y is 11; Then a becomes 10;
	return 0;
}

6.4 ~ symbol introduction

~Bitwise inversion,

Process explanation:

1 Binary
00000000000000000000000000000001
 Complement
00000000000000000000000000000001((the complement of a positive number is the original code)
Bitwise inversion
11111111111111111111111111111110((complement of result)
10000000000000000000000000000001((original code obtained by complement)

In doing questions, there are questions that require us to continuously read in data.
Directly on the template
while(scanf("%d",&n) != EOF)
Explanation:

If scanf reads in the value, the return value is 1, and while will loop all the time
If no value is read in, the return value is - 1, and the EOF value is - 1. At this time, while terminates the loop

Another template is
while(~scanf("%d",&n))

7. Relational operators

Relational operator

>
>=
<
<=
!=   Used to test "inequality"
==      Used to test "equal"

These relational operators are relatively simple and have nothing to say, but we should pay attention to some pitfalls in the use of operators. For example:
Warning:
In the process of programming = = and = are written incorrectly, resulting in errors.
if(n == 5)
if (n = 5) is different.

if(n == 5)If n The value of 5 holds
if(n = 5)Must be established, because n=5 The value of this expression is non-zero
if(n = 0)Certainly not, because n=0 The expression for is 0

Summary: if What is judged is the value of the expression
 Available later if(5 == n)To judge, because if written, n = 5 No
 stand

8. Logical operators

What are the logical operators

&&Logic and
||Logical or

Distinguish logical and bitwise AND
Distinguish between logical or and bitwise OR

1&2----->0
1&&2---->1 
1|2----->3 
1||2---->1

General examples of C language, question 9

Characteristics of logical and or:

#include <stdio.h>
int main()
{
	int i = 0, a = 0, b = 2, c = 3, d = 4;
	i = a++ && ++b && d++;
	//i = a++||++b||d++;
	printf("a = %d\n b = %d\n c = %d\nd = %d\n", a, b, c, d);
	return 0;
}
//What is the result of the program output?

Summary:
Logic and: exit when a valid expression is encountered
Logical or: exit when an expression does not hold

9. Conditional operator

exp1 ? exp2 : exp3

practice:

1.
if (a > 5)
        b = 3;
else
        b = -3;
What is it like to convert to a conditional expression?
2.Use conditional expression to find the larger value of two numbers
Conditional expression
b = a > 5 ? 3 : -3;

10. 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.

//Code 1
int a = 1;
int b = 2;
int c = (a > b, a = b + 10, a, b = a + 1);//comma expression 
c How much is it?
//Code 2
if (a = b + 1, c = a / 2, d > 0)
//Code 3 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
}

give an example:

(5,2) And (3, 6) who is older?
According to the comma expression, if the value of the expression is the last, the latter is larger

11. Subscript references, function calls and structure members

1. [] subscript reference operator
Operand: an array name + an index value

int arr[10];//Array creation
 arr[9] = 10;//Practical subscript reference operator.
 [ ]The two operands of are arr And 9.

2. () function call operator
Accept one or more operands: the first operand is the function name, and the remaining operands are the parameters passed to the function.

#include <stdio.h>
void test1()
{
	printf("hehe\n");
}
void test2(const char* str)
{
	printf("%s\n", str);
}
int main()
{
	test1();            //Utility () as a function call operator.
	test2("hello bit.");//Utility () as a function call operator.
	return 0;
}

3. Visit members of a structure

. structure member name
->Structure pointer - > member name

#include <stdio.h>
struct Stu
{
	char name[10];
	int age;
	char sex[5];
	double score;
};
void set_age1(struct Stu stu) {
	stu.age = 18;
}
void set_age2(struct Stu* pStu) {
	pStu->age = 18;//Structure member access
}
int main()
{
	struct Stu stu;
	struct Stu* pStu = &stu;//Structure member access

	stu.age = 20;//Structure member access
	set_age1(stu);

	pStu->age = 20;//Structure member access
	set_age2(pStu);
	return 0;
}

12. 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.

12.1 implicit type conversion

The integer arithmetic operation of C is always performed at least with the precision of the default integer type.
To achieve this precision, the characters and short operands in the expression are converted to normal integers before use. This conversion is called integer
promote.

Significance of integer improvement:

The integer operation of the expression shall be executed in the corresponding operation device of the CPU, and the byte length of the operand of the integer operator (ALU) in the CPU
Generally, it is the byte length of int and the length of the general register of CPU.
Therefore, even if the two char types are added, they will actually be converted to the standard length of integer operands in the CPU when executed by the CPU
Degrees.
General purpose CPU (general purpose CPU) is difficult to directly realize the direct addition of two 8-bit bytes (although machine instructions
There may be such byte addition instructions in). Therefore, all integer values whose length may be less than int length in the expression must be converted first
Change to int or unsigned int, and then send it to the CPU to execute the operation.

//Example 1
char a,b,c;
...
a = b + c;

b and c The value of is promoted to a normal integer, and then the addition operation is performed.
After the addition operation is completed, the result will be truncated and then stored in a in

How to carry out the overall improvement?

The integer promotion is promoted according to the = = sign bit (also the highest bit) = = of the data type of the variable

//Shaping and lifting of negative numbers
char c1 = -1;
variable c1 Binary bit of(Complement)There are only 8 bits in:
1111111
 because char Is signed char
 Therefore, when shaping and lifting, the high supplementary symbol bit is 1
 The result of the promotion is:
11111111111111111111111111111111
//Positive integer lifting
char c2 = 1;
variable c2 Binary bit of(Complement)There are only 8 bits in:
00000001
 because char Is signed char
 Therefore, when shaping and lifting, the high supplementary symbol bit is 0
 The result of the promotion is:
00000000000000000000000000000001
//Unsigned shaping lifting, high complement 0

Examples of shaping and lifting:

//Example 1
int main()
{
	char a = 0xb6;(A bit in hexadecimal=Four positions of binary)
	short b = 0xb600;
	int c = 0xb6000000;
	if (a == 0xb6)
		printf("a");
	if (b == 0xb600)
		printf("b");
	if (c == 0xb6000000)
		printf("c");
	return 0;
}

In example 1, a and B need shaping and lifting, but c does not need shaping and lifting
a. After the shaping and promotion of B, it becomes a negative number, so the result of the expression a = = 0xb6 and B = = 0xb600 is false, but the shaping and promotion of c does not occur, then the table
The result of the expression c==0xb6000000 is true
The output of the program is:

c

//Example 2

int main()
{
 char c = 1;
 printf("%u\n", sizeof(c)); 1
 printf("%u\n", sizeof(+c)); 4
 printf("%u\n", sizeof(-c)); 4
 return 0; }

In example 2, as long as c participates in the expression operation, it will be raised, and the expression + c will be raised, so sizeof(+c) is 4 bytes
The expression - c will also be raised, so sizeof(-c) is 4 bytes, but sizeof © , Just one byte

12.2 arithmetic conversion

If the operands of an operator are of different types, the operation cannot be performed unless one of the operands is converted to the type of the other operand. The following hierarchy is called ordinary arithmetic conversion.

From high to low
long double
double
float
unsigned long int
long int
unsigned int
int

If the type of an operand ranks low in the above list, it must first be converted to the type of another operand and then perform the operation.
Warning:
But the arithmetic conversion should be reasonable, otherwise there will be some potential problems

float f = 3.14;
int num = f;//Implicit conversion, there will be precision loss

12.3 properties of operators

There are three factors that affect the evaluation of complex expressions.

  1. operator precedence
  2. Associativity of operators
  3. 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.

Some problematic expressions

The evaluation part of the expression is determined by the priority of the operator.
Expression 1 
a*b + c*d + e*f

Note: when calculating code 1, because the priority of code 1 is higher than +, it can only ensure that the calculation of * is earlier than + but the priority does not determine that the third one is executed earlier than the first one.

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 of + operator is evaluated before or after the right operand, so the result is unpredictable and ambiguous.

//Code 3 - illegal expression
int main()
{
	int i = 10;
	i = i-- - --i * (i = -3) * i++ + ++i;
	printf("i = %d\n", i);
	return 0;
}

Expression 3 has different test results in different compilers

//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.

//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.


VS

See if the same code produces different results. Why?
Take a brief look at the assembly code You can analyze it clearly
When the first + in this code is executed, whether the third + + is executed is uncertain, because it depends on the priority of the operator
And associativity cannot determine the order of the first + and the third pre + +.

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.

Keywords: C Back-end

Added by atawmic on Thu, 24 Feb 2022 17:53:35 +0200