由ANSI标准定义的C语言关键字共32个:
*auto double int struct break else long switch
*case enum register typedef char extern return union
*const float short unsigned continue for signed void
*default goto sizeof volatile do if while static
1.数类型关键字(12)
数据类型关键字共12个
char、short、int、long、signed、unsigned、float、double、struct、union、enum、void
(1)unsigned :无符号的
用来声明一个无符号的变量。
unsigned char var; //var的范围:0~255
(2)signed :有符号的(可以省略不写)
用来声明一个有符号的变量。
signed char var; //var的范围:-128~127
(3)char :字符型
用来声明一个字符型变量。
占一个字节空间
char var;
(4)int :整型
用来声明一个整型变量。
C51:占两个字节空间,ARM:占四个字节
int var;
(5)float :浮点型
用来声明一个浮点型(实型)变量。
最多能表示到7个有效数据位。
占四个字节空间
float var;
(6)double :双精度型
//用来声明一个双精度实型变量。
//最多能表示到15~16个有效数据位。
//占四个字节空间 ,有的系统占八个字节
double var;
(7)short :短整型
用来声明一个短整型变量。
C51:跟int一样,ARM:占两个字节
short var;
(8)long :长整型
用来声明一个长整型变量。
ARM:跟int一样,C51:占四个字节
long var;
(9)void :空型
表示一个函数没有返回值,或者无形参。
void function(void);
(10)struct
用来声明一种结构体类型。
struct stu{
char sex;
int age;
float score;
struct stu *Next;
};
struct stu var;
(11)union
用来声明一种共用体类型。
该类型的变量所在空间的大小以其成员占最大的那个为准,
存入该变量中的值以程序中最后存入的数值为当前值
union non{
char sex;
int age;
float score;
};
union non var;
(12)enum
用来声明一种枚举类型。
规定枚举类型的变量,只能在限定的范围内取值
否则,编译会出现警告(达到数据安全的效果)
enum em
{a = 23,b,c,d = 56,e}; //其中b=24,c=25,e=57
enum em var;
2.流程控制关键字(12)
1、循环控制(5个)
for、do、while、break、continue
C语言中有三种循环语句:while循环、do-while循环和for循环。continue和break的不同之处在于其是跳过本次循环进入下一次循环,而break则是直接跳出循环。
2、条件语句(3个)
if、else、goto
(1)if,else语句
要注意,else总是与离它最近的未被匹配的if相匹配。
if (表达式)
语句1;
else
语句2;
//多分支
if (表达式1)
语句1;
else if (表达式2)
语句2;
else
语句3;
//嵌套
if (表达式1) {
语句1;
if (表示式x) {
语句x;
}
else {
语句y;
}
}
else if (表达式2) {
语句2;
}
else {
语句3;
}
(2)goto语句
goto语句可以实现跳转,跳转到标签所在位置,但是不能跨代码块实现:
int main()
{
int i = 0;
START:
printf("[%d]goto running ... \n", i);
Sleep(1000);
++i;
if (i < 10) {
goto START;
}
printf("goto end ... \n");
system("pause");
return 0;
}
3、开关语句(3个)
switch、case、default
首先switch括号内表达式应该是整形表达式或者一个整型值
case则是对应的整型表达式的值或者对应的整型值,根据表达式的值转到对应的case语句。
break是用来跳出switch语句。每个case语句后都加上break。
而default是为了处理case语句中没有的特殊情况。
int main()
{
int day = 1;
switch (day) {
case 1:
printf("星期一\n");
break;
case 2:
printf("星期二\n");
break;
case 3:
printf("星期三\n");
break;
case 4:
printf("星期四\n");
break;
case 5:
printf("星期五\n");
break;
case 6:
printf("星期六\n");
break;
case 7:
printf("星期日\n");
break;
default:
printf("bug!\n");
break;
}
system("pause");
return 0;
}
4、返回语句(1个)
return
return用于终止一个函数,并返回其后面跟随的值。例如:
char* show()
{
char str[] = "hello world";
return str;
}
int main()
{
char* s = show();
printf("%s\n", s);
system("pause");
return 0;
}
3.存储类型关键字(5)
auto、extern、register、static、typedef
(1)auto关键字
在代码块内部定义的变量是局部变量,而局部变量默认是用auto修饰的,但是一般都会省略。
#include <stdlib.h>
#include <stdio.h>
int main()
{
auto int j = 0;
printf("%d\n",j);
system("pause");
return 0;
}
(2)extern关键字
extern变量称为外部存储变量,extern声明了程序中将要用到但尚未定义的外部变量。通常外部储存都用于声明在另一个转换单元中定义的变量。
一个工程是由多个c文件组成的。这些源代码文件会分别进行编译,然后链接成一个可执行的模块。把这样的一个程序作为一个工程进行管理,并且生成一个工程文件来记录所有包含源代码文件。如下图,main.c和time.c中的变量互相调用
(3)register关键字
register:这个关
键字请求编译器尽可能地将变量存在CPU内部寄存器中,而不是通过内存寻址访问以提高效率。注意是尽可能,不是绝对。可以想象,一个CPU的寄存器数量有限,也就那么几个或几十个,如果用户定义了很多很多register变量,会把CPU的寄存器占满。
同时register变量是不能被取地址的。因为取地址这种寻址操作只能在内存中进行。
#include <stdlib.h>
#include <stdio.h>
#include "Test.h"
int main()
{
register int a = 27;
printf("a = %p\n",a);
system("pause");
return 0;
}
同时,使用寄存器变量时应该注意以下几点:
1.应当使用局部变量,因为全局变量会导致寄存器被长时间占用,可能会对计算机的状态造成影响。
2.应当在需要高频使用的时候用register关键字修饰局部变量。
3.如果要使用,也应当注意不能过多使用,因为寄存器数量是有限的,同时大都用来存储一些重要的状态信息
(4)static关键字
static变量为静态变量,将函数的内部变量和外部变量声明成static的意义是不一样的。
static的两个重要作用:
1、修饰变量。变量又分为局部变量和全局变量,但它们都存在内存的静态区。
(1)修饰全局变量:
static修饰的全局变量只能够在本文件内部被使用。
(2)修饰局部变量:
对于局部变量来说,其生命周期是在定义的代码块内部。但是如果用static修饰局部变量。其生命周期就会变成全局变量的生命周期。但是要注意,虽然其生命周期发生改变,但是其作用域却不发生改变。
#include <stdlib.h>
#include <stdio.h>
#include <stdio.h>
void AddOne(){
static int j = 0; //定义static变量
j = j + 1;
printf("%d\n", j);
}
int main(){
printf("第一次调用:");
AddOne();
printf("第二次调用:");
AddOne();
return 0;
}
可见static int j = 0;
只在第一次调用时初始化。
2、修饰函数。函数前加static使得函数成为静态函数。但此处“static”的含义不是指存储方式,而是指对函数的作用域仅局限于本文件(所以又称内部函数)。使用内部函数的好处是:不同的人编写不同的函数时,不用担心自己定义的函数是否会与其他文件中的函数同名。
(5)typedef关键字
typedef是用来对类型进行重命名的:
对一般类型进行重命名
对结构体类型进行重命名
对指针进行重命名
对复杂结构进行重命名
可参考第 八、typedef关键字
4.其他关键字( 3 个)
const、volatile、sizeof
(1)const关键字
const是constant的缩写,是恒定不变的意思,也翻译为常量和常数等。
const修饰的变量,不可直接被修改。但是却可以通过指针的解引用来进行修改。
const修饰指针变量分为几种情况:
const int *p;
// p 可变,p 指向的对象不可变
int const *p;
// p 可变,p 指向的对象不可变
int *const p;
// p 不可变,p 指向的对象可变
const int *const p;
//指针 p 和 p 指向的对象都不可变
同时const也可以修饰函数参数,const 修饰符也可以修饰函数的返回值,返回值不可被改变。例如:
const int Fun (void);
也可以在另一连接文件中引用 const 只读变量:
extern const int i;
//正确的声明
extern const int j=10;
//错误!只读变量的值不能改变
(2)volatile关键字
volatile关键字和const一样是一种类型修饰符,用它修饰的变量表示可以被某些编译器未知的因素更改,比如操作系统、硬件或者其他线程等。遇到这个关键字声明的变量,编译器对访问该变量的代码就不再进行优化,从而可以提供对特殊地址的稳定访问。
例:
int i=10;
int j = i;//(1)语句
int k = i;//(2)语句
这时候编译器对代码进行优化,因为在(1)、(2)两条语句中,i 没有被用作左值。这时候编译器认为 i 的值没有发生改变,所以在(1)语句时从内存中取出 i 的值赋给 j 之后,这个值并没有被丢掉,而是在(2)语句时继续用这个值给 k 赋值。这是一种内存被“覆盖”的情况。**编译器不会生成出汇编代码重新从内存里取 i 的值,这样提高了效率。**但要注意:(1)、(2)语句之间 i 没有被用作左值才行。
再看另一个例子:
volatile int i=10;
int j = i; //(3)语句
int k = i; //(4)语句
volatile 关键字告诉编译器 i 是随时可能发生变化的,每次使用它的时候必须从内存中取出i的值,因而编译器生成的汇编代码会重新从 i 的地址处读取数据放在k中。这样看来,如果 i 是一个寄存器变量或者表示一个端口数据或者是多个线程的共享数据,就容易出错,所以说 volatile 可以保证对特殊地址的稳定访问。
所以,volatile可以忽略编译器优化,保持内存可见性。
(3)sizeof关键字
siezof的主要作用就是计算数据类型长度。
各个类型的字节数:
int main()
{
printf("char %d\n", sizeof(char)); //1
printf("short %d\n", sizeof(short)); //2
printf("int %d\n", sizeof(int)); //4
printf("long %d\n", sizeof(long)); //4
printf("long long %d\n", sizeof(long long)); //8
printf("float %d\n", sizeof(float)); //4
printf("double %d\n", sizeof(double)); //8
return 0;
}