C语言关键字

 

 z=x>y? x:y   // 把x和y中的大者赋给z

 

1.关键字变更历史

1999年12月16日,ISO推出了C99标准,该标准新增了5个C语言关键字:

inline restrict _Bool _Complex _Imaginary(注意bool 从来不是C语言的关键字)

 

2011年12月8日,ISO发布C语言的新标准C11,该标准新增了7个C语言关键字:

_Alignas _Alignof _Atomic _Static_assert _Noreturn _Thread_local _Generic

2.关键字列表

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

auto :声明自动变量

static :声明静态变量  

register:声明寄存器变量    

extern:声明变量或函数是在其它文件或本文件的其他位置定义

const :声明只读变量     

typedef:用以给数据类型取别名

switch :用于开关语句

case:开关语句分支

continue:提前结束本次循环,,不是终止整个循环,开始下一轮循环

break:跳出当前循环,提前终止当前整个循环

default:开关语句中的“其它”分支

do :循环语句的循环体

while :循环语句的循环条件

for:一种循环语句

if:条件语句 

else :条件语句否定分支(与 if 连用)

goto:无条件跳转语句

return :子程序返回语句(可以带参数,也可不带参数)

sizeof:计算数据类型或变量长度(即所占字节数)

char :声明字符型变量或函数返回值类型

int: 声明整型变量或函数

short :声明短整型变量或函数

long :声明长整型变量或函数返回值类型

float:声明浮点型变量或函数返回值类型

double :声明双精度浮点型变量或函数返回值类型

signed:声明有符号类型变量或函数

unsigned:声明无符号类型变量或函数

enum :声明枚举类型

struct:声明结构体类型

union:声明共用体类型

volatile:说明变量在程序执行中可被隐含地改变

void :声明函数无返回值或无参数,声明无类型指针

 

根据关键字的作用,可以将关键字分为数据类型关键字流程控制关键字两大类。
  1 数据类型关键字
  A基本数据类型(5个)
  void :声明函数无返回值或无参数,声明无类型指针,显式丢弃运算结果
  char :字符型类型数据,属于整型数据的一种
  int :整型数据,通常为编译器指定的机器字长
  float :单精度浮点型数据,属于浮点数据的一种
  double :双精度浮点型数据,属于浮点数据的一种


  B 类型修饰关键字(4个)
  short :修饰int,短整型数据,可省略被修饰的int。
  long :修饰int,长整形数据,可省略被修饰的int。
  signed :修饰整型数据,有符号数据类型
  unsigned :修饰整型数据,无符号数据类型


  C 复杂类型关键字(5个)
  struct :结构体声明

                 结构体变量所占内存长度是各成员占的内存长度之和。每个成员分别占有其自己的内存单元。而共用体变量所占的内存长度等于最长的成员的长度。       

 例:

一,先声明结构体类型,再定义该类型的变量

声明结构体类型:
struct Student
{
    int num;          / 学号为整数
    char name[20];    / 姓名为字符串
    char sex;         / 性别为字符串
    int age;          / 年龄为整型
    float score;      / 成绩为实型
    char addr[30];    / 地址为字符串
};                    / 注意最后有一个分号

上面只是声明了一个结构体类型,它相当于一个模型,并没有定义变量。

定义上面的变量:
struct Student student1,student2;

二,在声明结构体的同时定义变量
struct Student
{
    int num;          / 学号为整数
    char name[20];    / 姓名为字符串
    char sex;         / 性别为字符串
    int age;          / 年龄为整型
    float score;      / 成绩为实型
    char addr[30];    / 地址为字符串
}student1,student2;

三,不指定类型名而直接定义结构体类型变量
struct 
{
    int num;          / 学号为整数
    char name[20];    / 姓名为字符串
    char sex;         / 性别为字符串
    int age;          / 年龄为整型
    float score;      / 成绩为实型
    char addr[30];    / 地址为字符串
}student1,student2;

初始化和引用:
student1.num = 10010;
student1.birthday.month = 06;  如成员本身又属于一个结构体类型

结构体数组:

声明结构体:

struct person
{
    char name[20];
    int count;
};

定义结构体数组并初始化:

struct person a[3] = { {"Ling",0},{"Zhang",0},{"Xia",0}};
name = a[1].name;    即name为 zhang

结构体指针:

#include<stdio.h>
#include<string.h>
int main()
{
    struct Student                  / 声明结构体变量
    {
        long num;
        char name[20];
        char sex;
        float score;
    };
    struct Student stu_1;          / 定义struct Stdent类型的变量stu_1
    struct Student *p;             / 定义指向struct Student类型数据的指针变量p
    p = &st_1;                     / p指向stu_1

    stu_1.num = 10101;             / 对结构体变量的成员赋值
    strcpy(stu_1.name, "Li Lin");  / 用字符串复制函数给stu_1.name赋值
    stu_1.sex = 'M';
    stu_1.score = 89.5;

/ 以下三种输出方法等价,(*p)必须有括号,-> 为指向运算符
    printf("No:%ld\n name:%s\n sex:%c\n score:%5.1f\n" , stu_1.num ,stu_1.name , stu_1.sex, stu_1.score);                
    printf("No:%ld\n name:%s\n sex:%c\n score:%5.1f\n" , (*p).num , (*p).name ,  (*p).sex,  (*p).score);
    printf("No:%ld\n name:%s\n sex:%c\n score:%5.1f\n" , p->num ,p->name , p->sex, p->score);  

}

  union :共用体声明

        用同一段内存单元存放不同类型的变量。比如把一个短整型,一个字符型和一个实型变量放在同一个地址开始的内存单元中,3个变量在内存中占的字节数不同,但都从同一地址开始存放,也就是使用覆盖技术,后一个数据覆盖了前面一个数据。结构体变量所占内存长度是各成员占的内存长度之和。每个成员分别占有其自己的内存单元。而共用体变量所占的内存长度等于最长的成员的长度。   

例如:

一起声明和定义共用体:
union Data
{
    int i;                        / 表示不同类型的变量 i,ch,f可以存放到用一段存储单元中
    char ch;
    float f;
}a,b,c;                           / 在声明类型同时定义变量

也可以类型声明与定义分开:
union Data                        / 声明共用体类型
{
    int i;                        
    char ch;
    float f;
};

union Data a,b,c;                / 用共用体类型定义变量

引用:

a.i       (引用共用体变量中的整型变量i)
a.ch      (引用共用体变量中的字符变量ch)
a.f       (引用共用体变量中的实型变量f)

如:
union Data
{
    int i;
    char ch;
    float f;
}a;  

a.i = 97;

printf("%d",a.i);    (输出整数97)
printf("%c",a.ch);   (输出字符‘a’)
printf("%f",a.f);    (输出实数0.000000)

因为97是赋给a.i的,因此按整数形式存储在变量单元中,最后一个字节是“01100001”,
如果用%d输出整数97,用%c格式输出a.ch ,就会输出字符a。如果用%f格式输出a.f ,
系统就会按浮点数形式输出数值部分0,故输出0.000000.

(1)同一内存段可以用来存放几种不同类型的成员,但在每一瞬时只能存放其中一个成员,而不是同时存放几个。

(2)可以对共用体变量初始化,但初始化表中只能有一个常量。

(3)共用体变量中起作用的成员是最后一次赋值的成员,在对共用体变量中的一个成员赋值后,原有变量存储单元中的值就取代。

(4)共用体变量的地址和它的各成员的地址都是同一地址。

(5)不能对共用体变量名赋值,也不能企图引用变量名来得到一个值。


  enum :枚举声明

声明枚举变量:
enum Weekday
{
    sun,mon,tue,wed,thu,fri,sat
};

定义枚举变量:
enum Weekday workday,weekend;

也可以不声明有名字的枚举类型,而直接定义枚举变量:
enum 
{
    sun = 7,mon = 1,tue,wed,thu,fri,sat
}workday,weekend;
可以指定枚举元素的值sun=7,mon =1, 最后的sat会变为6,里面的元素自动加1

可用来作判断比较:
if(workday==mon)...
if(workday>sun)...

        (1) 枚举常量,不能对它们赋值;

        (2)每一个枚举元素都代表一个整数,C语言编译按定义时的顺序默认它们的值为0,1,2,3,4...;

        (3)也可以人为地指定枚举元素的数值,在定义枚举类型时显式地指定。

         (4)枚举元素可以用来作判断比较。


  typedef :声明类型别名
  sizeof :得到特定类型或特定类型变量的大小。获取了数据在内存中所占用的存储空间,以字节为单位来计数。


  D 存储级别关键字(6个)
  auto : 指定为自动变量,由编译器自动分配及释放。通常在栈上分配。在调用该函数时,系统会给这些变量分配存储空间,在函数调用结束是自动释放这些空间。程序中大多数变量属于自动变量,auto可以省略,如auto int a; 与int a;等价。属于动态存储空间。
  static : 指定为静态变量,分配在静态变量区,修饰函数时,指定函数作用域为文件内部。属于静态存储类别,静态局部变量的值在函 数调用完后占用存储单元不释放,保持上次调用结束时的值。属于静态存储区。

               如: int f(int a) 

                   {       int b=0;   

                        static c=3;   

                         b=b+1;                //每次调用该函数,b的值都为0+1     

                         c=c+1;              // 每次调用为c+1,如第一次赋值3,第二次调用为4=3+1,第三次调用为5=4+1 

                          return(a+b+c);

                    }  静态局部变量在编译时赋初值的只赋值一次,每次调用不再赋初值而只是保留上次调用结束时的值。如未明确初始化,它的字节都被设定为0。当调用次数多时往往弄不清楚静态变量的值是多少。而自动变量(上auto)每次调用函数时重新给一次初值。

                   在定义内部函数时,在函数名和函数类型的前面加static,如:static int fun(int a, int b); 表示fun 是一个内部函数,不能被其他文件调用,使函数的作用域仅限于所在文件,这样,在不同的文件中即使有相同名字的函数也互不干扰,这样就不必担心跟别人写的文件模块有相同函数名。
  register : 指定为寄存器变量,建议编译器将变量存储到寄存器中使用,也可以修饰函数形参,建议编译器通过寄存器而不是 堆栈传递参数。  一般情况下,变量的值是放在内存中的,当程序中用到变量值时,由控制器发出指令将内存中该变量的值送到运算器中,或存数时由运算器到内存(运算器<=>内存)。因寄存器的存取速度远高于对内存的存取速度,为提高执行效率,用register 声明,如: register int f; 寄存器存储在CPU中的寄存器。
  extern : 指定对应变量为外部变量,即在另外的目标文件中定义,可以认为是约定由另外文件声明的。表示把该变量的作用域 扩展到此位置,声明extern时,类型名可写可不写,因为它不是定义变量,可以不指定类型,如:在file1.c 中定义外部变量 int a ; 然后在file2.c中用extern int A; 或extern A; 把外部变量A作用域扩展到从此处开始。

                  如在file1.c中定义全局变量A时,使用了static声明,该变量只能用于本文件,再在file2.c中用extern A;就会发生错误。 可以在多人设计独立的模块程序时加入static声明,即使在多个文件中使用相同的外部变量名也不相干,可为程序的模 块化和通用性提供方便。

                  C语言规定,如果定义函数时省略extern,则默认为外部函数。比如可以在#nclude 的头文件中直接声明函数原型,而不用extern,然后在其他 文件中就可以调用。
  const : 与volatile合称“cv特性”,指定变量不可被当前线程/进程改变(但有可能被系统或其他线程/进程改变)。有类型,占存储空间,只是不允许改变其值。如const  float  pi=3.1416;         //行末有分号
  volatile : 与const合称“cv特性”,指定变量的值有可能会被系统或其他进程/线程改变,强制编译器每次从内存中取得该变量的值。(下面有详细解释)

2 流程控制关键字
  A 跳转结构(4个)
  return :用在函数体中,返回特定值(或者是void值,即不返回值)。跳出循环并且跳出函数,同时返回函数值。
  continue :结束当前循环(本次循环),开始下一轮循环,不是整个循环
  break :跳出当前循环(整个循环)或switch结构
  goto :把控制无条件转移到同一函数内的被标记的语句。不建议使用 goto 语句。因为它使得程序的控制流难以跟踪,使程序难以理解和难以修改。

               如:   

                   goto label; 

                  ...         

                 label:    下面执行函数

                 在这里,label 可以是任何除 C 关键字以外的纯文本,它可以设置在 C 程序中 goto 语句的前面或者后面

  B 分支结构(5个)
  if :条件语句
  else :条件语句否定分支(与if连用)
  switch :开关语句(多重分支语句)
  case :开关语句中的分支标记
  default :开关语句中的“其他”分治,可选。


  C 循环结构(3个)
  for :for循环结构,for(1;2;3)4;的执行顺序为1->2->4->3->2...循环,其中2为循环条件
  do :do循环结构,do 1 while(2); 的执行顺序是 1->2->1...循环,2为循环条件
  while :while循环结构,while(1) 2; 的执行顺序是1->2->1...循环,1为循环条件
  以上循环语句,当循环条件表达式为真则继续循环,为假则跳出循环。

 

这里可以提下volatile关键字

       更详细可参考:https://blog.csdn.net/qq_29350001/article/details/54024070

        volatile总是与优化有关,编译器有一种技术叫做数据流分析,分析程序中的变量在哪里赋值、在哪里使用、在哪里失效,分析结果可以用于常量合并,常量传播等优化,进一步可以消除一些代码。但有时这些优化不是程序所需要的,这时可以用volatile关键字禁止做这些优化。

  volatile的本意是“易变的” 因为访问寄存器要比访问内存单元快的多,所以编译器一般都会作减少存取内存的优化,但有可能会读取数据。当要求使用volatile声明变量值的时候,系统总是重新从它所在的内存读取数据,即使它前面的指令刚刚从该处读取过数据。精确地说就是,遇到这个关键字声明的变量,编译器对访问该变量的代码就不再进行优化,从而可以提供对特殊地址的稳定访问;如果不使用valatile,则编译器将对所声明的语句进行优化。(简洁的说就是:volatile关键词影响编译器编译的结果,用volatile声明的变量表示该变量随时可能发生变化,与该变量有关的运算,不要进行编译优化,以免出错)

变量如果加了 volatile 修饰,则会从内存重新装载内容,而不是直接从寄存器拷贝内容。

看两个事例:

1>  告诉compiler不能做任何优化

1

2

3

4

5

6

7

8

9

10

11

12

比如要往某一地址送两指令:

int *ip =...; //设备地址

*ip = 1//第一个指令

*ip = 2//第二个指令

以上程序compiler可能做优化而成:

int *ip = ...;

*ip = 2;

结果第一个指令丢失。如果用volatile, compiler就不允许做任何的优化,从而保证程序的原意:

volatile int *ip = ...;

*ip = 1;

*ip = 2;

即使你要compiler做优化,它也不会把两次付值语句间化为一。它只能做其它的优化。

2>  用volatile定义的变量会在程序外被改变,每次都必须从内存中读取,而不能重复使用放在cache或寄存器中的备份

1

2

3

4

5

6

7

8

9

10

11

12

13

volatile char a;

 

a=0;

 

while(!a)

{

 //do some things;

}

 

do other();

 

如果没有 volatile ,do other()不会被执行

 

 

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

虾稿

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值