Contents of this chapter
- Kind tips
- Key points of this chapter
- start of text
-
- 1. Classification of operators
- 2. Arithmetic operators
- 3. Bit shift operators
- 4. Bitwise operators
- 5. Assignment operator
- 6. Unary operators
- 7. Relational operators (the following operators do not appear in the catalog alone)
- 8. Logical operators
- 9. Conditional Operators
- 10. Comma expressions
- 11. Subscript references, function calls, and structure members
- 12. Expression evaluation
- end of text
Kind tips
Hello everyone, I am Cbiltps. In my blog, if there are sentences that are difficult to understand or key points that are difficult to express in words , I will have pictures . So my blog with pictures is very important ! ! !
If you are interested in me please see my first blog !
Key points of this chapter
- Introduction to various operators.
- expression evaluation
start of text
1. Classification of operators
- arithmetic operator
- shift operator
- bitwise operator
- assignment operator
- unary operator
- relational operator
- logical operator
- conditional operator
- comma expression
- Subscript references, function calls, and structure members
2. Arithmetic operators
Arithmetic operators are:
+ - * / %
In addition to%
the operator, several other operators can act on integers and floating-point numbers.
2.1 /
Operators
#include <stdio.h>
int main()
{
int ret = 9 / 2;//对于 /(除号) 两边都是整数,执行的整数除法
double ret2 = 9 / 2;//它的值是什么?
double ret3 = 9 / 2.0;//它的值是什么?
printf("%d\n", ret);
printf("%lf\n", ret2);
printf("%lf\n", ret3);
return 0;
}
The running results are as follows:
the second result is still 4.0
, why?
因为操作数中有浮点数,才执行浮点数除法。
2.2 %
Operators
%
The operator is the modulo operator , also known as the remainder operator .
int ret4 = 10 % 4;
printf("%d", ret4);//打印出来是2
Note: %
The operator can only be used for integer types
3. Bit shift operators
<< 左移操作符
>> 右移操作符
3.1 <<
Left shift operator
int a = 5;
int b = a << 1;
printf("%d\n", b);//打印出来的是 10
//要看懂下面的图解,要明白一些知识点:
//移位操作符,移动的是二进制位
//对于整数的二进制有3中表示形式:原码、反码、补码
//正整数 - 原码、反码、补码相同
//负整数
//原码 - 直接按照数字的正负写出的二进制序列
//反码 - 原码的符号位不变,其他位按位取法得到的
//补码 - 反码+1
//整数 在内存中存储的是二进制的补码
If it is a negative number, look at the code:
int c = -1;
int d = c << 1;
printf("%d\n", d);//打印的是原码的值,打印出来是 -2
//10000000000000000000000000000001 - 原码
//11111111111111111111111111111110 - 反码
//11111111111111111111111111111111 - 补码
Shift rules:左边抛弃、右边补0
Regarding the original code, inverse code, and complement code , please read another advanced blog I wrote !
3.2 >>
Left shift operator
Shift rules:
1. Logical shift: 左边用0填充,右边丢弃
2. Arithmetic shift:左边用原该值的符号位填充,右边丢弃
Example:
int a = 5;
int b = a >> 1;
printf("%d\n", b);//打印出来的是 2
Here's another example with negative numbers :
int c = -1;
int d = c << 1;
printf("%d\n", d);//打印出来还是 -1
Here, the original sign bit is added, so VS2019 uses arithmetic right shift!
Warnings ⚠:
1: For the shift operator, 不要移动负数位
, this is undefined by the standard.
2: Either 被移动数
or 移动的位数
must be an integer.
For example ( wrong demo):
int num = 10;
num>>-1;//error
4. Bitwise operators
Bitwise operators are:
&
bitwise AND|
bitwise or^
bitwise XOR
Note: Their operands must be integers.
4.1 &
Bitwise AND operator
Calculation rules:
1: As long as there is 0 on the binary bit, it is 0
2: Two of the binary bits are 1 at the same time, that is 1
int a = 3;
int b = -2;
int c = a & b;
printf("%d\n", c);//打印出来是 2
//%d - 说明我们要打印c的值,以有符号的形式
//00000000000000000000000000000011 -3的原码
//11111111111111111111111111111110 -2的补码
//00000000000000000000000000000010 这个数是2
4.2 |
Bitwise OR operator
Calculation rules: as long as there is 1 in the binary bit, it is 1
int a = 3;
int b = -2;
int c = a | b;
printf("%d\n", c);//打印 -1
//00000000000000000000000000000011 -3的原码
//11111111111111111111111111111110 -2的补码
//11111111111111111111111111111111
//11111111111111111111111111111111 补码
//11111111111111111111111111111110 反码
//10000000000000000000000000000001 原码 它的值是-1
4.3 ^
Bitwise XOR operator
Calculation rules: the same binary bit is 0, and the difference is 1
int a = 3;
int b = -2;
int c = a ^ b;//打印出来是 -3
printf("%d\n", c);
//00000000000000000000000000000011 -3的原码
//11111111111111111111111111111110 -2的补码
//11111111111111111111111111111101
//11111111111111111111111111111101 补码
//11111111111111111111111111111100 反码
//10000000000000000000000000000011 原码 它的值是-3
A perverted interview question:
A temporary variable (the third variable) cannot be created to exchange two numbers.
#include <stdio.h>
int main()
{
int a = 3;
int b = 5;
printf("交换前:a=%d b=%d\n", a, b);
a = a ^ b;
b = a ^ b;
a = a ^ b;
printf("交换后:a=%d b=%d\n", a, b);
return 0;
}
Idea diagram:
Note: The readability of the code written in this way is not good enough, and it only applies to integer types
5. Assignment operator
The assignment operator allows you to get a value that you were not satisfied with before, that is, you can reassign yourself .
int weight = 120;//体重
weight = 89;//不满意就赋值
double salary = 10000.0;
salary = 20000.0;//使用赋值操作符赋值
Assignment operators can be used consecutively, for example:
int a = 10;
int x = 0;
int y = 20;
a = x = y + 1;//连续赋值
How does this code feel?
Then write like this:
x = y + 1;
a = x;
Much cleaner and easier to debug .
Compound assignment operator:
- +=
- -=
- *=
- /=
- %=
- <<=
- &=
- |=
- ^=
These operators can be written as composite effects, such as:
int x = 10;
x = x + 10;
x += 10;//复合赋值
6. Unary operators
A unary operator is an operator with only one operand
6.1 Various unary operators
!
logical inversion
-
negative value
+
positive value
&
take address
&arr[0];//数组首元素的地址
&arr[9];//取出的是第10个元素的地址
&arr;//取出数组的地址
sizeof
the type length of the operand in bytes
- sizeof is an operator, not a function
- sizeof is to calculate the memory size (unit: byte) of a variable or type created variable, and the unit has nothing to do with what data is stored in the memory
//以下几种写法都是一样的
printf("%d\n", sizeof(a));//4
printf("%d\n", sizeof a);//4
printf("%d\n", sizeof(int));//4
//这里有一个问题;
int a = 5;
short s = 10;
printf("%d\n", sizeof(s = a + 2));//打印出来是 2
printf("%d\n", s); //打印出来是 10 因为:sizeof 内部的表达式不参与运算
~
Bitwise inverse of a number
- Including the sign bit can also be bitwise reversed
#incluide <stdio.h>
int main()
{
int a = 0;
//00000000000000000000000000000000
int b = ~a;
printf("%d\n", b);
//00000000000000000000000000000000
//11111111111111111111111111111111 所有位按位取反
//
//11111111111111111111111111111110 反码
//10000000000000000000000000000001 原码
//-1
return 0;
}
--
front, rear--
- Front - -: first - -, then use
int a = 10;
int b = a--;
printf("%d\n", b);//这里打印出来还是 10
- Back - -: use first, then - -
int a = 10;
int b = --a;
printf("%d\n", b);//这里打印出来才是9
++
front, rear++
- Pre ++: ++ first, then use
- Postfix ++: use first, then ++
Be careful : don't write code like this (garbage code), you will be fired by the company!
int main()
{
int a = 1;
int b = (++a) + (++a) + (++a);//err
printf("b=%d\n", b);
return 0;
}
The two compilers are different here!
*
Indirect access operator (dereference operator), can &
be used in conjunction with fetching address
( 类型
) type conversion
int a = (int)3.14;//默认写出的浮点数是double的,所以可以强制转换
printf("%d\n", a);
return 0;
6.2 sizeof and arrays
Let's look at a question and see how much they output respectively:
#include <stdio.h>
void test1(int arr[])//它的本质数是(int* arr[])
{
printf("%d\n", sizeof(arr));//传的是首元素的地址
}
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));//数组名单独放在sizeof内部,数组名表示整个数组
printf("%d\n", sizeof(ch));//(3)
test1(arr);
test2(ch);
return 0;
}
Output result:
For more knowledge about arrays , please see my last blog !
7. Relational operators (the following operators do not appear in the catalog alone)
Relational operators only make sense when compared between the same kind!
>
>=
<
<=
!=
for testing "not equal"==
for testing "equal"
These relational operators are relatively simple, there is nothing to talk about, but we should pay attention to the pitfalls when using some operators.
Note: When programming =
and ==
Wrong, it will lead to errors!
8. Logical operators
&&
Logical AND
If false always false:
int a = 0;
int b = 3;
int c = a && b;//只判断真假,所以打印出来是 0
||
Logical or
one true must be true:
int a = 0;
int b = 3;
int c = a || b;
printf("%d\n", c);//打印出来是 1
Let’s take a look at a 360 written test question:
#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);//打印出来的是1 2 3 4
return 0;
}
Diagram of thinking:
If it is logical or :
#include <stdio.h>
int main()
{
int i = 0, a = 0, b = 2, c = 3, d = 4;
i = a++ || ++b || d++;
printf(" a = %d\n b = %d \n c = %d\n d = %d\n", a, b, c, d);//打印错来的是1 3 3 4
return 0;
}
Idea diagram:
9. Conditional Operators
The conditional operator is also called the ternary operator
exp1 ? exp2 : exp3
int a = 0;
int b = 0;
if (a > 5)
b = 3;
else
b = -3;
//这里有更简单的写法:
(a > 5) ? (b = 3) : (b = -3);//直接搞定
10. Comma expressions
exp1, exp2, exp3, …expN
Comma expressions are multiple expressions separated by commas.
Comma expression rules: 从左向右依次执行,整个表达式的结果是最后一个表达式的结果
.
Code demo:
//代码1
int a = 1;
int b = 2;
int c = (a>b, a=b+10, a, b=a+1);//c是多少?看的是最后一个表达式
//代码2
if (a =b + 1, c=a / 2, d > 0)//最后一个表达式判断的是 d > 0
//代码3
a = get_val();
count_val(a);
while (a > 0)//注意;这样写非常的冗余
{
//业务处理
a = get_val();
count_val(a);
}
//如果使用逗号表达式,改写:
while (a = get_val(), count_val(a), a > 0)
{
//业务处理
}
11. Subscript references, function calls, and structure members
[ ]
Subscript reference
operator Operands: an array name + an index value
int arr[10];//创建数组
arr[9] = 10;//实用下标引用操作符。
//[ ]的两个操作数是arr和9。
//下面表达的意思都是相同的
arr[4] -- > *(arr+4) --> *(4+arr) --> 4[arr]
( )
function call operator
Accepts one or more operands : the first operand is the function name, and the remaining operands are the parameters passed to the function.
void test()
{
printf("hehe\n");
}
int main()
{
test();//这里就是函数调用操作符
return 0;
}
结构成员访问操作符
.
Struct variable.Member name->
Structure pointer -> member name
#include <stdio.h>
struct Book
{
char name[20];
float price;
char id[10];
};
void print1(struct Book b)
{
printf("书名: %s\n", b.name);//在这里访问结构体成员
printf("价格: %f\n", b.price);
printf("书号: %s\n", b.id);
//*(b.name);
}
void print2(struct Book* pb)
{
/*printf("书名: %s\n", (*pb).name);
printf("价格: %f\n", (*pb).price);
printf("书号: %s\n", (*pb).id);*/
printf("书名: %s\n", pb->name);//也可以这样访问
printf("价格: %f\n", pb->price);
printf("书号: %s\n", pb->id);
}
int main()
{
struct Book b = {
"C语言程序设计", 55.5f, "C20190201"};
print2(&b);
//print1(b);
//结构成员访问操作符
//结构变量.成员名
//结构体指针->成员名
//(*结构体指针).成员名
return 0;
}
12. Expression evaluation
The order in which expressions are evaluated is determined in part by the precedence and associativity of operators . Likewise, operands of some expressions may need to be converted to other types during evaluation .
12.1 Implicit type conversions
Integer arithmetic in C is always performed with at least the precision of the default integral type .
To achieve this precision, character and short integer operands in expressions are converted to plain integer types before use , a conversion known as integer promotion .
Significance of integer promotion:
The integer operation of the expression must be executed in the corresponding operation device of the CPU. The byte length of the operand of the integer arithmetic unit (ALU) in the CPU is
generally the byte length of int, and it is also the length of the general-purpose register of the CPU.
Therefore, even if the addition of two char types is performed by the CPU, it must first be converted to the standard length of the integer operand in the CPU
.
It is difficult for a general-purpose CPU (general-purpose CPU) to directly add two 8-bit bytes (although there
may be such byte addition instructions in machine instructions). Therefore, the various integer values in the expression whose length may be smaller than int must be converted
to int or unsigned int before being sent to the CPU for calculation.
How to carry out overall improvement?
整形提升是按照变量的数据类型的符号位来提升的
- Integer promotion for negative numbers:
char c1 = -1;
//变量c1的二进制位(补码)中只有8个比特位:
//1111111
//因为 char 是有符号的 char
//所以整形提升的时候,高位补充符号位,即为1
//提升之后的结果是:
//11111111111111111111111111111111
- Integer promotions for positive numbers:
char c2 = 1;
//变量c2的二进制位(补码)中只有8个比特位:
//00000001
//因为 char 是有符号的 char
//所以整形提升的时候,高位补充符号位,即为0
//提升之后的结果是:
//00000000000000000000000000000001
Notice:无符号整形提升,高位补0
//举例:
#include <stdio.h>
int main()
{
char a = 3;//a是1byte - 8bit
//00000000000000000000000000000011
//00000011 - a
char b = 127;//b是1byte - 8bit
//00000000000000000000000001111111
//01111111 - b
//a和b都是char类型,自身大小的都是1byte,所以这里计算的时候要进行整型提升
//00000000000000000000000000000011 a整形提升
//00000000000000000000000001111111 b整形提升
//00000000000000000000000010000010 相加后
//
char c = a + b;
//10000010 - c
//11111111111111111111111110000010 整形提升后的是补码
//11111111111111111111111110000001 反码
//10000000000000000000000001111110 原码
//-126
printf("%d\n", c);
return 0;
}
The values of a and b are promoted to ordinary integers before the addition operation is performed;
after the addition operation is complete, the result is truncated before being stored in c.
12.2 Arithmetic conversions
If the operands of an operator are of different types, the
operation cannot proceed unless one of the operands is converted to the type of the other. The hierarchy below is called ordinary arithmetic conversions .
1.long double
2.double
3.float
4.unsigned long int
5.long int
6.unsigned int
7.int
If the type of an operand ranks lower in the above list, it must first be converted to the type of the higher-level operand before performing the operation.
int a = 4;
float f = 4.5f;
float r = a + f;
//a首先转换成 float类型 然后和f相加
Warning: Arithmetic conversions need to be reasonable, otherwise there are some potential problems.
float f = 3.14;
int num = f;//这样隐式转换,会有精度丢失
12.3 Properties of operators
There are three factors that affect the evaluation of complex expressions:
- operator precedence
- operator associativity
- whether to control the order of evaluation
Which of two adjacent operators is executed first?
取决于他们的优先级;如果两者的优先级相同,取决于他们的结合性
.
//两个相邻的操作符:
int a = 2;
int b = 4;
int c = a * b + 3;// * 的优先级比 + 高,所以先算乘法,再算加法
//两者的优先级相同:
int a = 2;
int b = 4;
int c = a + b + 3;//两者优先级相同,看它们的结合性(看下面的操作符优先级表),所以是从左到右加
Operator precedence table ( 由高到低展示
):
Then, think about it, are you able to perform calculations after you have mastered the operators 优先级
, 结合性
, and what 是否控制求值顺序
was mentioned earlier in the expression? is the only result?整型提升
算数转换
Unified answer:答案是否定的
Look at a few problematic expressions:
//表达式的求值部分由操作符的优先级决定
//问题表达式1:
a*b + c*d + e*f
Note: When calculating code 1, since * has a higher priority than +, it can only be guaranteed that the calculation of * is earlier than +, but the priority cannot determine that the third * is
executed earlier than the first +.
//问题表达式2
c + --c;
Note: As above, the priority of the operator can only determine the operation of the self-decrement – in front of the operation of +, but we have no way
to know acquisition of the left operand of the + operator is evaluated before or after the right operand , so the result is unpredictable and ambiguous
.
//问题代码3-非法表达式
int main()
{
int i = 10;
i = i-- - --i * (i = -3) * i++ + ++i;
printf("i = %d\n", i);
return 0;
}
Some big guys tested the results under different compilers and found that they are different!
There are many more examples, so I won't list them one by one!
Finally, make a summary: 我们写出的表达式如果不能通过操作符的属性确定唯一的计算路径,那这个表达式就是存在问题的
.