============================== 2022-7-15 ==============================
一.温故知新 权限的补充(特殊的权限)
suid u+s (可执行的命令文件中加入u+s)
sgid g+s (目录文件中加入g+s)
sticky o+t (目录文件中加入o+t)
umask值
666 - 0002 = 664
777 - 0002 = 775
进程的介绍
ps -aux
kill PID
Linux下的C语言 #include <stdio.h>
int main(void)
{
printf("Hello World!");
}
函数的返回值类型 函数名 (参数列表)
{
代码
}
int main (void)
{
printf("Hello World!");
}
'\0' '\n' '\r' '\t' '\v'
ASCII(常用ASCII表有128个字符<又补充到了256个字符>)
'\0' 0
'\n' 10
'0' 48
'A' 65
'a' 97
标准化输出格式
%+某一个东西
%d
%c
%f
%s
%p
%%
%o
%x
VT控制码
变量 1.变量的含义
变量是用来存储数据的
(会把数据存储到内存中<以二进制补码的形式存储>)
2.变量的定义
数据类型 变量名 ;
1)基本数据类型
整型 有符号/无符号 short int long
实型 有符号 float double
字符型 有符号/无符号 char
2)通过sizeof运算符进行测试
测试出的结果以字节为单位
1字节 = 8位
sizeof(char) = 1
sizeof(short) = 2
sizeof(int) = 4
sizeof(long) = 8
sizeof(float) = 4
sizeof(double) = 8
测试的结果并不唯一,会随着硬件或者操作系统有所变化
3)变量名的命名要求
1>变量名是由数字 字母 下划线组成,但不能以数字开头
2>变量名是区分大小写的
3>变量名不能与C语言的关键字重复
4>变量名要做到见名生义
3.变量的存储
char c = 13;
//将来会把十进制整数13转换成8位的二进制的数据存储到
//c变量所占用的1个字节的存储空间中
0 0 0 0 1 1 0 1
在二进制数据中,最左边的是最高位
在二进制数据中,最右边的是最低位
第7位 0
第6位 0
第5位 0
第4位 0
第3位 1
第2位 1
第1位 0
第0位 1
如果是有符号类型,最高位是符号位,其余位是数据位
第7位 符号位 (0代表正数 1代表负数)
第6-0位 数据位
unsigned char c = 13;
无符号的数据类型所以范围是[0 ~ 255]
float f = 3.2;
有符号的数据类型
float在内存中占用4个字节存储空间(32bit)
第31位 符号位
第30位 浮点偏移量的位
第29-23位 整数位
第22-0位 小数位
f = 3.2
000000011
0.2 * 2 = 0.4 0
0.4 * 2 = 0.8 0
0.8 * 2 = 1.6 1
0.6 * 2 = 1.2 1
0.2 * 2 = 0.4 0
变量会存储在内存中,以二进制补码的形式进行存储
原码 : 把操作数从别的进制转化成二进制,就是原码
程序员要的是原码(printf打印出的数据是原码数据)
补码 : 如果操作数为正,那么原码等于补码
如果操作数为负,那么原码不等于补码,需要转换
无论是原码转换成补码,还是补码转换成原码,公式都一样
除了符号位不变,其他位按位取反,再加1
计算机要补码(计算机在计算的时候需要用补码计算)
为什么使用补码存储数据?
1)保证0的唯一性
2)为了保证加法运算的合理
1-1 -> 1 + (-1)
0001 + 1001 = 1010 = -2
0001 + 1111 = 0000 = 0
存储 二转十 进制间转换 按位取反
4.变量的初始化
数据类型 变量名 = 数值 ;
char c = 13 ;
int a = 9527 ;
float f = 3.14 ;
5.变量的定义和变量的初始化有什么区别?
变量的定义 : 只是在内存中分配了相应的存储单元,
存储空间中是垃圾值
变量的初始化 : 除了在内存中分配了相应的存储单元,
也在存储空间中保存了初始值
注意 : 当你定义变量时一定要有初始化
6.变量的使用规则
1)变量要先定义再使用
(把变量的定义放到main函数的开头的位置)
2)不同类型的变量有不同的运算要求
3)变量在定义时在内存中占用的空间大小就已经确定了
1 2 3 4 5 6 7 8 9 10 11 12 13 14 #include <stdio.h> #include <stdlib.h> int main (int argc, char *argv[]) { printf ("sizeof(char) = %ld\n" , sizeof (char )); printf ("sizeof(short) = %ld\n" , sizeof (short )); printf ("sizeof(int) = %ld\n" , sizeof (int )); printf ("sizeof(long) = %ld\n" , sizeof (long )); printf ("sizeof(float) = %ld\n" , sizeof (float )); printf ("sizeof(double) = %ld\n" , sizeof (double )); return 0 ; }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 #include <stdio.h> #include <stdlib.h> int main (int argc, char *argv[]) { char c = -1 ; printf ("c = %p\n" , c); return 0 ; }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 #include <stdio.h> #include <stdlib.h> int main (int argc, char *argv[]) { char c = -13 ; printf ("c = %p\n" , c); return 0 ; }
面试题
1.进制之间转换
八进制<------->二进制<-------->十六进制
^
|
V
十进制
1)十进制转换成二进制 除以2取余
2)二进制转换成十进制 2的n次方
2.除了常用进制以外,笔试题会考三进制 五进制 七进制 十五进制
============================================
作业:
1.把今天讲过的内容完完整整的复习一遍
2.多做一些进制之间转换的题目
============================================
int i = 100;
int i = 'a';
char c = 13;
char c = 'A';//char = 1/4int
scanf函数 函数功能 : 用来接收键盘录入的函数
scanf("%d", &i);
注意:
1.在scanf函数的双引号中只写标准化输出格式即可
2.在scanf函数的双引号中不要加换行符
3.在scanf函数的双引号之后需要的是地址
gcc编译器是不检查段错误(由于操作内存不当引起的)的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 #include <stdio.h> #include <stdlib.h> int main (int argc, char *argv[]) { int i = 0 ; printf ("i = %d\n" , i); printf ("请输入变量i的值:" ); scanf ("%d" , i); printf ("i = %d\n" , i); return 0 ; }
算术运算符 + 加法
- 减法
* 乘法
/ 除法(取商)
% 除法(取余/取模)
注意 :
除法运算中,除数不能为0
int a = 13, b = 7, sum = 0;
sum = a + b;
sum = a - b;
sum = a * b;
sum = a / b;//a所在的位置是被除数,b所在的位置是除数
sum = a % b;//a所在的位置是被除数,b所在的位置是除数
如果在除法运算中,被除数 小于 除数, 商是0, 余数是被除数本身
sum = 7 / 13;// sum = 0
sum = 7 % 13;// sum = 7
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 #include <stdio.h> #include <stdlib.h> int main (int argc, char *argv[]) { int a = 7 , b = 13 ; printf ("a + b = %d\n" , a + b); printf ("a - b = %d\n" , a - b); printf ("a * b = %d\n" , a * b); printf ("a / b = %d\n" , a / b); printf ("a %% b = %d\n" , a % b); return 0 ; }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 #include <stdio.h> #include <stdlib.h> int main (int argc, char *argv[]) { int sum = 0 ; scanf ("%d" , &sum); printf ("千位 : %d\n" , sum / 1000 ); printf ("百位 : %d\n" , sum / 100 % 10 ); printf ("十位 : %d\n" , sum / 10 % 10 ); printf ("个位 : %d\n" , sum % 10 ); return 0 ; }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 #include <stdio.h> #include <stdlib.h> int main (int argc, char *argv[]) { int a = 0 , b = 0 ; int tmp = 0 ; scanf ("%d-%d" , &a, &b); 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 ; }
关系运算符 > 是否大于
< 是否小于
== 是否相等
>= 是否大于等于
<= 是否小于等于
!= 是否不等于
一个表达式经过关系运算符的运算,最终会生成真假值
0为假,非0为真
默认的真值是1
1 2 3 4 5 6 7 8 9 10 11 12 13 14 #include <stdio.h> #include <stdlib.h> int main (int argc, char *argv[]) { printf ("13 > 7 = %d\n" , 13 > 7 ); printf ("13 < 7 = %d\n" , 13 < 7 ); printf ("13 == 7 = %d\n" , 13 == 7 ); printf ("13 >= 7 = %d\n" , 13 >= 7 ); printf ("13 <= 7 = %d\n" , 13 <= 7 ); printf ("13 != 7 = %d\n" , 13 != 7 ); return 0 ; }
逻辑运算符 && 逻辑与 表达式1 && 表达式2
全真才为真,有假就是假
|| 逻辑或 表达式1 || 表达式2
全假才为假,有真就是真
! 逻辑非 !(表达式)
真假互换
表达式1 && 表达式2
如果表达式1为真,会执行表达式2的内容
如果表达式1为假,不会执行表达式2的内容
表达式1 || 表达式2
如果表达式1为真,不会执行表达式2的内容
如果表达式1为假,会执行表达式2的内容
-----------------------
1.罗列一下判断是否是闰年的条件
(能被4整除但是不能被100整除 或者 能被400整除)
(year % 4 == 0 && year % 100 != 0) || (year%400==0)
2.罗列三角形的条件(普通 直角 等腰 等边)
a b c
a + b > c && a + c > b && b + c > a
a * a + b * b == c * c ||
a * a + c * c == b * b ||
b * b + c * c == a * a
a == b || a == c || b == c
a == b && a == c
-----------------------
1 2 3 4 5 6 7 8 #include <stdio.h> #include <stdlib.h> int main (int argc, char *argv[]) { return 0 ; }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 # 赋值运算符 = += -= *= /= %= <<= ... 会把赋值运算符右边的项先进行计算, 再赋值给赋值运算符左边的项(左值) a += 1 ; int a = 10 ; a *= 2 + 3 ; a = 50 ```C #include <stdio.h> #include <stdlib.h> int main(int argc, char *argv[]) { return 0 ; }
条件运算符 也是C语言唯一的一个三目运算符
? :
part.1 ? part.2 : part.3;
如果part.1为真,会执行part.2的内容
如果part.1为假,会执行part.3的内容
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 #include <stdio.h> #include <stdlib.h> int main (int argc, char *argv[]) { int a = 0 , b = 0 ; int min = 0 ; scanf ("%d-%d" , &a, &b); min = a < b ? a : b; printf ("min = %d\n" , min); return 0 ; }
1 2 3 4 5 6 7 8 9 10 11 12 13 #include <stdio.h> #include <stdlib.h> int main (int argc, char *argv[]) { int year = 0 ; scanf ("%d" , &year); (year%4 ==0 &&year%100 !=0 )||(year%400 ==0 )?printf ("%d年是闰年\n" , year) : printf ("%d年是平年\n" , year); return 0 ; }
强制类型转换 (数据类型)
可以把操作的内容临时的强制转换成某种数据类型
将来会在底层内核驱动大量使用强制类型转换的运算符
1 2 3 4 5 6 7 8 9 10 11 #include <stdio.h> #include <stdlib.h> int main (int argc, char *argv[]) { float f = 3.14 ; printf ("f = %d\n" , (int )f); return 0 ; }
自增自减运算符 ++ 自增
-- 自减
如果a++或者++a自己为独立的一条语句,执行时没有区别
如果和别的语句一起使用,会有区别
a++ : 先使用a的值做操作,再自增
++a : 先自增,再使用a的值做操作
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 #include <stdio.h> #include <stdlib.h> int main (int argc, char *argv[]) { int a = 0 ; printf ("a++ = %d\n" , a++); a = 0 ; printf ("++a = %d\n" , ++a); return 0 ; }
注意 : 作为嵌入式开发工程师,2的0次方 ~ 2的10次方
在底层内核驱动中做位运算需要保证是在无符号的环境中进行运算
位运算符
<< 按位左移
会把操作数的二进制位,每一位都进行左移的操作
在某种程度上来说,按位左移相当于是乘法运算
左移多少位就相当于乘以2的多少次方
char c = 13;
c <<= 3;//c * 2的3次方 = 13 * 8 = 104
>> 按位右移
会把操作数的二进制位,每一位都进行右移的操作
在某种程度上来说,按位右移相当于是除法运算(取商)
右移多少位就相当于 / 2的多少次方,取商
& 按位与
全1才是1,有0就是0
| 按位或
全0才是0,有1就是1
~ 按位取反(每一位都要取反)
0变成1,1变成0
^ 按位异或
相同为0,不同为1
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 #include <stdio.h> #include <stdlib.h> int main (int argc, char *argv[]) { char c = 13 ; printf ("c = %d\n" , c); c = c << 8 ; printf ("c = %d\n" , c); return 0 ; }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 #include <stdio.h> #include <stdlib.h> int main (int argc, char *argv[]) { char c = 13 ; printf ("c = %d\n" , c); c = c >> 2 ; printf ("c = %d\n" , c); return 0 ; }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 #include <stdio.h> #include <stdlib.h> int main (int argc, char *argv[]) { char a = 13 , b = 7 ; char c = 0 ; printf ("c = %d\n" , c); c = a & b; printf ("c = %d\n" , c); c = a | b; printf ("c = %d\n" , c); return 0 ; }
1 2 3 4 5 6 7 8 9 10 11 12 13 #include <stdio.h> #include <stdlib.h> int main (int argc, char *argv[]) { char c = 13 ; printf ("c = %d\n" , c); c = ~c; printf ("c = %d\n" , c); return 0 ; }
char c = 13;
原码 0 0 0 0 1 1 0 1
补码 0 0 0 0 1 1 0 1
~
补码 1 1 1 1 0 0 1 0
原码 1 0 0 0 1 1 1 0
c = -14
char c = -13; c = ~c;
原码 1 0 0 0 1 1 0 1
补码 1 1 1 1 0 0 1 1
~
补码 0 0 0 0 1 1 0 0
原码 0 0 0 0 1 1 0 0
c = 12
1 2 3 4 5 6 7 8 9 10 11 #include <stdio.h> #include <stdlib.h> int main (int argc, char *argv[]) { unsigned char c = -2 ; printf ("c = %d\n" , c); return 0 ; }
unsigned char c = -1;
原码 1 0 0 0 0 0 0 1
补码 1 1 1 1 1 1 1 1
printf("c = %d\n", c);
c = 255
unsigned char c = -2;
原码 1 0 0 0 0 0 1 0
补码 1 1 1 1 1 1 1 0
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 #include <stdio.h> #include <stdlib.h> int main (int argc, char *argv[]) { char a = 13 , b = 7 ; char c = 0 ; printf ("c = %d\n" , c); c = a ^ b; printf ("c = %d\n" , c); return 0 ; }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 #include <stdio.h> #include <stdlib.h> int main (int argc, char *argv[]) { char c = -13 ; printf ("c = %d\n" , c); c <<= 4 ; printf ("c = %d\n" , c); return 0 ; }
位运算符的真正使用 注意:
1.在做位运算时,只改变要操作的位,其他位要保持不变
2.如果想要置1用按位或
3.如果想要清0用按位与
4.按位或上0,会保持不变
5.按位与上1,会保持不变
6.如果一次性想要操作多个位,一定要先清零再赋值
1.例如:GPIOA是一个32bit的寄存器,
现在想要把该寄存器的第3位置1
GPIOA |= (1 << 3);
--------------------------------------------------
1 00000000 00000000 00000000 00000001
1<<3 00000000 00000000 00000000 00001000
|
GPIOA XXXXXXXX XXXXXXXX XXXXXXXX XXXX#XXX
=
GPIOA XXXXXXXX XXXXXXXX XXXXXXXX XXXX1XXX
--------------------------------------------------
2.例如:GPIOA是一个32bit的寄存器,
现在想要把该寄存器的第4位清0
GPIOA &= ~(1 << 4);
--------------------------------------------------
1 00000000 00000000 00000000 00000001
1<<4 00000000 00000000 00000000 00010000
~(1<<4) 11111111 11111111 11111111 11101111
&
GPIOA XXXXXXXX XXXXXXXX XXXXXXXX XXX#1XXX
=
GPIOA XXXXXXXX XXXXXXXX XXXXXXXX XXX01XXX
--------------------------------------------------
3.例如:GPIOA是一个32bit的寄存器,
现在想要把该寄存器的第11 10 9 8位变为1010
GPIOA &= ~(15 << 8);
GPIOA |= (10 << 8);