Linux下C语言教程-李慧芹老师-第二章
目录
第二章 数据类型,运算符和表达式
数据类型(基本数据类型)
数据类型所占字节数随机器硬件不同而不同,以
int
为基准,char
比它小,float
和double
比它大。
所占字节数
存储区别
不同类型的数据间转换(隐式和显式=>强制类型转换)
特殊性
布尔型(
bool
):false
:0
,true
:非零值。float
类型,不够精确,其实是一个小范围。1
2
3
4
5
6
7
8
9
10int func(float f)
{
if (f < 0)
return -1;
// else if (f == 0)
else if (fabs(f - 0) <= 1e-6)
return 0;
else
return 1;
}char
型是否有符号,未定义不同形式的零值
0
,'0'
,"0"
,'\0'
,NULL
数据类型得与后续代码的输入输入相匹配(自相矛盾)
常量与变量
常量
定义
在程序执行过程中值不会发生变化的量。
分类
整型常量:1,790,76
实型常量:3.14,5.26
字符常量:由单引号引起来的单个字符或转义字符,如
'a'
,'X'
,'\n'
,'\ddd'
(d可以是0-7
,三位八进制,例如'\015'
),'\xhh'
(h可以是0-F
,二位十六进制,'\x7f'
)字符串常量:由双引号引起来的一个或多个字符组成的序列(特殊情况,空串),如:
""
,"a"
,"abXYZ"
,"abc\n\021\018"
(注意这个字符串,\n
,\021
都是算单个字符,\018
又不算)
我问gpt,”\018”在C语言几个字符。
在C语言中,字符串是以字符数组的形式表示,而每个字符串的末尾都有一个特殊的字符'\0'
(空字符),用于标识字符串的结束。当你提到的"\018"
在C语言中出现时,它表示一个包含特殊字符的字符串字面量。具体来说,
\0
在C语言中是一个转义字符,用于表示字符串的结束符(null terminator)。该符号用于标记字符串的结束,确保字符串处理函数如printf
、strcpy
等知道在哪里停止处理。在
"\018"
中,\0
表示字符串的结束,后面跟的18
并不会作为字符串的一部分来处理。因此,如果你在C语言中使用"\018"
,它实际上会被视为只包含一个空字符(\0
)的字符串。这意味着,尽管看起来字符串中有更多的字符,但由于\0
的存在,它实际上在C语言处理中表示一个空字符串。总结来说,在C语言中
"\018"
实际上会被看作一个包含单一结束字符(null terminator)的字符串,而不是包含多个字符。这种处理方式是因为C语言使用空字符来标记字符串的结束。
标识常量:
#define
特点:完整的用宏体替换宏名,不做任何检查。
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
34
35
36
37
38
39#include <stdio.h>
#include <stdlib.h>
#define PI 3.14
#define ADD 2 + 3
#define ADD1 (2 + 3)
#define MAX(a, b) (a > b ? a : b)
#define MAX1(a, b) ((a) > (b) ? (a) : (b))
int main()
{
// printf("%d\n", ADD * ADD);
// 相当于 2+3*2+3
// 故输出11而不是25
// printf("%d\n", ADD1 * ADD1);
// 相当于(2+3)*(2+3)
// 正常输出25
int i = 5, j = 3;
// printf("%d\n", MAX(i, j));
// 输出5
// printf("%d\n", MAX(i, j * 2));
// 输出6
printf("i=%d\tj=%d\n", i, j);
printf("%d\n", MAX1(i++, j++));
printf("i=%d\tj=%d\n", i, j);
// 输出:
// i = 5 j = 3
// 6
// i = 7 j = 4
// 为什么i自增了两次?
// 预处理结果
// printf("%d\n", ((i++) + (j++) ? (i++) : (j++)));
exit(0);
}解决办法:
- 使用函数:函数与宏的区别在于,一个占用编译时间,一个占用运行时间。在
linux
内核中多用宏。 - 在宏中进行变量保存,这种写法超出标准C,属于
GNU C
的扩展部分,只能在支持的编译器(如gcc
)中使用,在linux
内核中非常常用。
1
2
3
4
5
6
7
8
9
10
11
12#define MAX2(a, b) \
({ \
int A = a, B = b; \
((A) > (B) ? (A) : (B)); \
})
#define MAX3(a, b) \
({ \
typeof(a) A = a, B = b; \
((A) > (B) ? (A) : (B)); \
})- 使用函数:函数与宏的区别在于,一个占用编译时间,一个占用运行时间。在
变量
用来保存一些特定内容,并且在程序执行过程中值随时会发生变化的量。
定义
[存储类型] | 数据类型 | 标识符 | = | 值 |
---|---|---|---|---|
TYPE | NAME | = | VALUE |
- 标识符:由字母,数字,下划线组成且不能以数字开头的一个标识序列。拟定时尽量做到见名知义。
- 数据类型:基本数据类型、构造类型
- 值:注意匹配
- 存储类型:
auto
,static
,register
,extern
(说明型)auto
:默认,自动分配空间,自动回收空间。register
:(建议型,编译器不一定采用)寄存器类型,只能定义局部变量,不能定义全局变量;大小有定义,只能定义32位大小的数据类型,如double
就不可以;集尘器没有地址,所以一个寄存器类型的变量无法打印出地址查看或使用。static
:静态型,自动初始化为0值或空值,并且变量的值有继承性。另外,常用来修饰一个变量和函数,防止其对外扩散。extern
:说明型,意味着不能改变被说明的变量的值或类型。
1 |
|
变量的生命周期与作用范围
- 全局变量和局部变量
- 局部变量和局部变量
- 参考图片存储类型比较
这一块具体讲解见代码仓库
/Chapter2/变量/
。
在minproj
例子中,如果在proj.c
和proj.h
中static
定义func
函数,而在main.c
中调用func
。
1 |
|
运算符和表达式
表达式和语句的区别
运算符部分
每个运算符所需要的参与运算的操作数个数
结合性
优先级
运算符的特殊用法
如:
%
(要求左右两边都是整形),=
与==
,逻辑运算(&&
和||
)的短路特性位运算的重要性
<< >> ~ | ^ &
将操作数中第n位置1,其他位不变:
num = num | 1 << n;
将操作数中第n位清0,其他位不变:
num = num & ~(1 << n);
测试第n位:
if(num & 1 << n)
从一个指定宽度的数中取出某几位:
1
2
3
4
5// 假设取一个32位整数的第10位到第15位
unsigned int number;
unsigned int mask = ((1 << 6) - 1) << 9; // 6 是位数(15-10+1),9 是起始位置(10-1)
unsigned int result = number & mask;
result = result >> 9;
运算符相关代码
1 |
|