0%

03c_02day

==============================
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);
//%p可以打印出变量在内存中是如何存储的
/*
c = 0xff;//1111 1111
char c = -1;
原码 1 0 0 0 0 0 0 1
补码 1 1 1 1 1 1 1 1
*/

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);
//%p可以打印出变量在内存中是如何存储的
/*
c = 0xff;//1111 1111
char c = -1;
原码 1 0 0 0 0 0 0 1
补码 1 1 1 1 1 1 1 1

char c = -128;
原码 1 0 0 0 0 0 0 0
补码 1 0 0 0 0 0 0 0
0x80

char c = -13;
原码 1 0 0 0 1 1 0 1
补码 1 1 1 1 0 0 1 1
c = 0xf3
*/

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\n", &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);
//通过scanf函数为sum变量录入4位的正整数
//atoi(); itoa();
/* itoa();
9527 -> "9527"
9527 / 1000 = 9 + '0' = '9'
9527 / 100 % 10 = 5 + '0' = '5'
9527 / 10 % 10 = 2 + '0' = '2'
9527 % 10 = 7 + '0' = '7'
*/
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和b的值
/*
tmp = a;
a = b;
b = tmp;
*/

a = a + b;//a = 13 + 7 = 20
b = a - b;//b = 20 - 7 = 13
a = a - b;//a = 20 - 13 = 7

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; // a = a + 1;
int a = 10;
a *= 2 + 3;// a = 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;//00001101

printf("c = %d\n", c);

//c = c << 2;//00110100->32+16+4=52
//c = c << 3;//01101000->64+32+8=104
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;//00001101

printf("c = %d\n", c);

c = c >> 2;//00000011

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;
/*
a 0 0 0 0 1 1 0 1
&
b 0 0 0 0 0 1 1 1
=
c 0 0 0 0 0 1 0 1
*/

printf("c = %d\n", c);

c = a | b;
/*
a 00001101
|
b 00000111
=
c 00001111
*/
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;//00001101

printf("c = %d\n", c);
c = ~c; //11110010->-114
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;
/*
a 00001101
^
b 00000111
=
c 00001010
*/

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;
/*
c = -13
原 1 0 0 0 1 1 0 1
补 1 1 1 1 0 0 1 1
c << 4
补 0 0 1 1 0 0 0 0
原 0 0 1 1 0 0 0 0
c = 48
*/
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);