一、关键字signed、unsigned
1、signed:有符号数,此标识可以省略,默认有符号数。(符号占1位)
- 1.signed char: 8位有符号数,范围-27 ~ (27 -1)。
- 2.signed int:32位有符号数,范围-231 ~ (231 -1)。
2、unsigned:无符号数,必须注明。
- 1.unsigned char:8位无符号数,范围0~(28 -1)。
- 2.unsigne int:32位无符号数,范围0~(232-1)。
二、关键字auto、static
1、auto 自动变量
- 局部变量,所有非声明为static的存储类别都是为自动变量,自动变量的定义关键字可省略,其特点为动态分配存储空间,自动变量编译器不对其进行初始化,需要人为对其赋值,每次函数调用结束时,都会立即释放,下次再调用时又会再次对其赋值一次。
2、static 静态变量
- 普通局部变量不使用关键字static来修饰变量,编译器一般不对变量进行初始化,也就是它的初始值是不确定的,除非对其显式赋值;如果使用static来定义变量(则为静态局部变量),即使在声明时未对其赋值,编译器也会把它初始为0,且静态局部变量储存于进程的全局数据区,即使函数返回,它的值也保持不变(简单理解为普通变量每次函数调用一次时就初始化一次,但是静态变量则只初始化一次,就算再次调用也不会再次初始化一次,而是保存上一次调用结束时的值)。
1、修饰变量:存在内存静态区。
- 静态局部变量:规范作用域和生存期。
- 静态全局变量:规范作用域。
2、修饰函数:规范函数作用域
三、关键字const
- 关键字const是constant的缩写,是恒定不变的意思。用const来修饰一个变量时,只能赋值一次,只读变量,不能修改,存放在静态区的全局只读变量。
- const可以修饰变量、数组、指针、函数参数等。
- const靠近谁就是修饰谁,例如void fun(const int i);跟const int fun(void);第一个是指形参不能修改,而第二个是指函数的返回值不能修改,需要区分。
四、关键字volatile
- volatile提醒编译器它后面所定义的变量随时都有可能改变,因此编译后的程序每次需要存储或读取这个变量的时候,告诉编译器对该变量不做优化,都会直接从变量内存地址中读取数据,从而可以提供对特殊地址的稳定访问。
- 如果没有volatile关键字,则编译器可能优化读取和存储,可能暂时使用寄存器中的值,如果这个变量由别的程序更新了的话,将出现不一致的现象。(简洁的说就是:volatile关键词影响编译器编译的结果,用volatile声明的变量表示该变量随时可能发生变化,与该变量有关的运算,不要进行编译优化,以免出错)
- 例子或者详细可参考https://zhuanlan.zhihu.com/p/343688629
五、关键字typedef
- typedef是给一个已经存在的数据类型(是类型而不是变量)去一个别名而不是定义一个新的数据类型。
六、关键字extern
- 在定义变量的时候,extern可以被省略(定义时,默认均省略);在声明变量的时候,这个extern必须添加在变量前,所以有时会让你搞不清楚到底是声明还是定义。或者说,变量前有extern不一定就是声明,而变量前无extern就只能是定义。注:定义要为变量分配内存空间;而声明不需要为变量分配内存空间。
1、变量
extern int a; // 声明一个全局变量 a
int a; // 定义一个全局变量 a
extern int a =0 ; // 定义一个全局变量 a 并给初值。
int a =0; // 定义一个全局变量 a, 并给初值,
第四个等于第三个,都是定义一个可以被外部使用的全局变量,并给初值。
糊涂了吧,他们看上去可真像。但是定义只能出现在一处。也就是说,不管是int a;还是extern int a=0;还是int a=0;都只能出现一次,而那个extern int a可以出现很多次。
当你要引用一个全局变量的时候,你就必须要声明,extern int a; 这时候extern不能省略,因为省略了,就变成int a;这是一个定义,不是声明。注:extern int a; 中类型 int 可省略,即 extern a; 但其他类型则不能省略。
2、函数
- 由于函数的定义和声明是有区别的,定义函数要有函数体,声明函数没有函数体(还有以分号结尾),所以函数定义和声明时都可以将extern省略掉,反正其他文件也是知道这个函数是在其他地方定义的,所以不加extern也行。两者如此不同,所以省略了extern也不会有问题。
/*fun.h*/
int fun(void); //函数声明,所以省略了extern,完整些是extern int fun(void);
/*对应的fun.c文件*/
int fun(void)
{
return 0;
}//一个完整的全局函数定义,因为有函数体,extern同样被省略了。
3、总结
- 对变量而言,如果你想在本源文件(例如文件名A)中使用另一个源文件(例如文件名B)的变量,方法有2种:(1)在A文件中必须用extern声明在B文件中定义的变量(当然是全局变量);(2)在A文件中添加B文件对应的头文件,当然这个头文件包含B文件中的变量声明,也即在这个头文件中必须用extern声明该变量,否则,该变量又被定义一次。
对函数而言,如果你想在本源文件(例如文件名A)中使用另一个源文件(例如文件名B)的函数,方法有2种:(1)在A文件中用extern声明在B文件中定义的函数(其实,也可省略extern,只需在A文件中出现B文件定义函数原型即可);(2)在A文件中添加B文件对应的头文件,当然这个头文件包含B文件中的函数原型,在头文件中函数可以不用加extern。
- 参考http://lpy999.blog.163.com/blog/static/117372061201182051413310/
七、关键字struct
- 结构体struct是一种构造类型,它是由若干个相互关联的成员组成的,每个成员可以是一个基本数据类型,也可以是数组、指针或者又是一个构造类型。
struct 结构体名
{
成员表列
}变量名表列;
八、关键字union
- 共用体:把不同类型的数据存放到用一段内存单元中,这些不同类型的的数据分时共享同一段内存单元。
- 共用体长度是成员列表中长度最长的成员长度。
union 共用体名
{
成员表列
}变量名表列;
九、关键字enum
- enum枚举类型的元素是固定的常量的集合。
enum
{
MON=1, TUE, WED, THU, FRI, SAT, SUN
} day;
十、关键字if、else
1、判断语句if、else
- 如果布尔表达式为 true,则执行 if 块内的代码。如果布尔表达式为 false,则执行 else 块内的代码。
C 语言把任何非零和非空的值假定为 true,把零或 null 假定为 false。
if(boolean_expression)
{
/* 如果布尔表达式为真将执行的语句 */
}
else
{
/* 如果布尔表达式为假将执行的语句 */
}
2、判断语句if、else if
- 一个 if 语句后可跟一个可选的 else if…else 语句,这可用于测试多种条件。
当使用 if…else if…else 语句时,以下几点需要注意:
- 一个 if 后可跟零个或一个 else,else 必须在所有 else if 之后。
- 一个 if 后可跟零个或多个 else if,else if 必须在 else 之前。
- 一旦某个 else if 匹配成功,其他的 else if 或 else 将不会被测试。
if(boolean_expression 1)
{
/* 当布尔表达式 1 为真时执行 */
}
else if( boolean_expression 2)
{
/* 当布尔表达式 2 为真时执行 */
}
else if( boolean_expression 3)
{
/* 当布尔表达式 3 为真时执行 */
}
else
{
/* 当上面条件都不为真时执行 */
}
十一、关键字switch、case
- 多分支选择语具,提高分支结构的效率。
- 语法
switch(expression){
case constant-expression :
statement(s);
break; /* 可选的 */
case constant-expression :
statement(s);
break; /* 可选的 */
/* 您可以有任意数量的 case 语句 */
default : /* 可选的 */
statement(s);
}
- switch 语句中的 expression 是一个常量表达式,必须是一个整型或枚举类型。
- 在一个 switch 中可以有任意数量的 case 语句。每个 case 后跟一个要比较的值和一个冒号。
- case 的 constant-expression 必须与 switch 中的变量具有相同的数据类型,且必须是一个常量或字面量。
- 当被测试的变量等于 case 中的常量时,case 后跟的语句将被执行,直到遇到 break 语句为止。
- 当遇到 break 语句时,switch 终止,控制流将跳转到 switch 语句后的下一行。
- 不是每一个 case 都需要包含 break。如果 case 语句不包含 break,控制流将会 继续 后续的 case,直到遇到 break 为止。
- 一个 switch 语句可以有一个可选的 default case,出现在 switch 的结尾。default case 可用于在上面所有 case 都不为真时执行一个任务。default case 中的 break 语句不是必需的。
十二、关键字do、for、while
- C语言有3种循环语句:while、do~while、for。
1、循环语句do~while
do
{
statement(s);
}while( condition );
- 条件表达式出现在循环的尾部,所以循环中的 statement(s) 会在条件被测试之前至少执行一次。如果条件为真,控制流会跳转回上面的 do,然后重新执行循环中的 statement(s)。这个过程会不断重复,直到给定条件变为假为止。
2、循环语句while
while(condition)
{
statement(s);
}
- statement(s) 可以是一个单独的语句,也可以是几个语句组成的代码块。
- condition 可以是任意的表达式,当为任意非零值时都为 true。当条件为 true 时执行循环。 当条件为 false 时,退出循环,程序流将继续执行紧接着循环的下一条语句。
- while 循环的关键点是循环可能一次都不会执行。当条件为 false 时,会跳过循环主体,直接执行紧接着 while 循环的下一条语句。
3、for循环
- for 循环允许您编写一个执行指定次数的循环控制结构。
for ( init; condition; increment )
{
statement(s);
}
- init 会首先被执行,且只会执行一次。这一步允许您声明并初始化任何循环控制变量。您也可以不在这里写任何语句,只要有一个分号出现即可。
- 接下来,会判断 condition。如果为真,则执行循环主体。如果为假,则不执行循环主体,且控制流会跳转到紧接着 for 循环的下一条语句。
- 在执行完 for 循环主体后,控制流会跳回上面的 increment 语句。该语句允许您更新循环控制变量。该语句可以留空,只要在条件后有一个分号出现即可。
- 条件再次被判断。如果为真,则执行循环,这个过程会不断重复(循环主体,然后增加步值,再然后重新判断条件)。在条件变为假时,for 循环终止。
4、嵌套循环
- 一个循环体内又包含一个完整的循环结构就叫做循环嵌套。
- 建议循环次数多的放在嵌套循环内层,次数少的放在外层,能减少CPU运行负担。
- 循环最好不超过3层,如果需要多次嵌套,可以将循环做成子程序进行调用。
- 详细参考https://www.runoob.com/cprogramming/c-nested-loops.html
十三、关键字break
- C语言中break语句有以下两种用法:
- 当 break 语句出现在一个循环内时,循环会立即终止,且程序流将继续执行紧接着循环的下一条语句。
- 它可用于终止 switch 语句中的一个 case。
- 如果您使用的是嵌套循环(即一个循环内嵌套另一个循环),break 语句会停止执行最内层的循环,然后开始执行该块之后的下一行代码。
十四、关键字continue
-
C 语言中的 continue 语句有点像 break 语句。但它不是强制终止,continue 会跳过当前循环中的代码,强迫开始下一次循环。
-
对于 for 循环,continue 语句执行后自增语句仍然会执行。对于 while 和 do…while 循环,continue 语句重新执行条件判断语句。