更多课程 选择中心

C/C++培训
达内IT学院

400-996-5531

C语言有哪些关键词,C语言44个关键词大全

  • 发布:C++培训
  • 来源:学习笔记
  • 时间:2020-05-29 17:12

目前而言(2017年5月18日) C语言中有 32 + 5 + 7 = 44 个关键字. 具体如下

-> C89关键字

char short int unsigned
long float double struct
union void enum signed
const volatile typedef auto
register static extern break
case continue default do
else for goto if
return switch while sizeof

-> C99新增关键字

_Bool _Complex _Imaginary inline restrict

-> C11新增关键字

_Alignas _Alignof _Atomic _Generic _Noreturn _Static_assert _Thread_local

 下面容我细细分析起具体用法.(存在平台差异, 有问题特别欢迎评论补充, 这就相当于一个关键字字典)

 

C89 32个关键字

1) char

解释:

声明变量的时候用! char占1字节, 8bit. 多数系统(vs or gcc)上是有符号的(arm 上无符号), 范围是[-128, 127]. 

在工程项目开发中推荐用 

#include <stdint.h>int8_t-> signedcharuint8_t-> unsignedchar

扯淡一点, 程序开发最长遇到的就是自解释问题. 鸡生蛋, 蛋生鸡. 后面再分析 signed 和 unsigned

演示:

#include <stdio.h>charc; c=getchar(); rewind(stdin); printf("c = %d, c = %c.\n", c);

 

2) short

解释:

声明变量的时候用! short 占2字节, 为无符号的. 默认自带signed. 范围[-2^15, 2^15 - 1] 2^15 = 32800.

推荐使用 int16_t or uint16_t 类型.

演示:

shortport =8080; printf("port = %d.\n", port);

 

3) int

解释:

声明变量的时候用! int 声明的变量, 占4字节, 有符号. 范围 [-2^31, 2^31-1].

推荐用 int32_t 和 uint32_t类型开发. 方便移植

演示:

inthoge =24; printf("hoge = %d.\n", hoge);

 

4) unsigned

解释:

变量类型修饰符! 被修饰的变量就是无符号的.范围 >= 0.  unsigned 只能修饰整型的变量.

当然当你用这个修饰变量的时候. 再使用 - 和 -- 运算的时候一定要小心

演示:

unsignedinti =0;//正确unsignedshorts =0;//正确unisgnedfloatf =0.11f;//错误

 

5) long

解释:

声明变量的时候用!长整型 x86上四字节, x64上8字节. 一定不比int字节数少.  C99之后出现long long类型8字节.

演示:

longl =4;longlongll =l; printf("l = %ld, ll = %lld.\n", l, ll);

 

6) float

解释:

声明变量的时候用! 四字节. 精度是6-7位左右.  详细精度可以看 float与double的范围和精度

演示:

floatf = -0.12f;//四字节longfloatlf =0;//八字节 等同于 double, 不推荐这么写

 

7) double

解释:

声明变量的时候用!八字节,精度在15-16位左右.有的时候压缩内存用float代替.

演示:

doubled = 2e13;//8字节longdoubleld = -0.99;//x86也是8字节, 不推荐这么用longlongdoublelld =99;//写法错误, 不支持

 

8) struct

解释:

定义结构体, 这个关键字用法广泛, 是大头. c 的重要思路就是面向过程编程. 撑起面向过程的大头就是结构体.

struct 就是定义结构的东西, 可以看看下面演示

演示:

复制代码
//普通结构体定义structnode {intid;structnode *next; };structnode node = {1, NULL };//匿名结构定义struct{intid;char*name; } per= {2,"王志"};
复制代码

 

9) union

解释:

定义公用体, 用法很花哨. 常在特殊库函数封装中用到.技巧性强

演示:

复制代码
//普通定义union type {charc;inti;floatf; }; union type t= { .f =3.33f};//匿名定义union { ... } t ={ .... };//类型匿名定义structcjson {structcjson * next;//采用链表结构处理, 放弃二叉树结构, 优化内存structcjson * child;//type == ( _CJSON_ARRAY or _CJSON_OBJECT ) 那么 child 就不为空unsignedchartype;//数据类型和方式定义, 一个美好的意愿char* key;//json内容那块的 key名称union {char* vs;//type == _CJSON_STRING, 是一个字符串doublevd;//type == _CJSON_NUMBER, 是一个num值, ((int)c->vd) 转成int 或 bool}; };
复制代码

再来一种 union用法, 利用内存对齐. 

复制代码
//12.0 判断是大端序还是小端序,大端序返回trueinlineboolsh_isbig(void) {staticunion { unsignedshort_s; unsignedchar_c; } _u= {1};return_u._c ==0; }
复制代码

还有很久以前利用union 实现内存字节对齐, 太多了. 每个关键字用法, 确实很多, 很意外.

 

10) void

解释:

这个是空关键字. 用法很多. 也是我最喜欢的关键字. 用在函数声明中, 类型定义中.

演示:

复制代码
//函数声明externvoidfoo();//函数参数约束externvoidfoo(void);//()中加了void表示函数是无参的, 否则是任意的//万能类型定义, 指针随便转void* arg = NULL;
复制代码

 

11) enum

解释:

枚举类型, C中枚举类型很简陋. 其实就相当于一种变相的INT宏常量. 估计这也许也是 INT宏常量和枚举并存的原因.

演示:

复制代码
////flag_e - 全局操作基本行为返回的枚举, 用于判断返回值状态的状态码//>= 0 标识 Success状态, < 0 标识 Error状态//typedefenum{ Success_Exist= +2,//希望存在,设置之前已经存在了.Success_Close = +1,//文件描述符读取关闭, 读取完毕也会返回这个Success_Base = +0,//结果正确的返回宏Error_Base= -1,//错误基类型, 所有错误都可用它, 在不清楚的情况下Error_Param = -2,//调用的参数错误Error_Alloc = -3,//内存分配错误Error_Fd = -4,//文件打开失败} flag_e;
复制代码

枚举变量完全可以等同于 int 变量使用, 枚举值等同于宏INT常量使用. 枚举的默认值是以1位单位从上向下递增.

 

12) signed

解释:

变量声明类型修饰符. 有符号型, 对比 unsigned 无符号型. 变量声明默认基本都是 signed, 所以多数别人就省略了.

演示:

signedintpiyo =0x1314520; signedchar* str = u8"你好吗";

当然了, 平时不需要刻意加. 会让人嫌麻烦. O(∩_∩)O哈哈~

 

13) const

解释:

const修饰的变量表示是个不可修改的量. 和常量有点区别. 可以简单认为 const type val 是个只读的.

演示:

复制代码
//声明不可修改的量constintage =24;//修饰指针constint* pi = NULL;//*pi 不能修改指向变量int*constpt = NULL;//pt 不能指向新的指针constint*constpc = NULL;//*pc 和 pc 都不能动
复制代码

其实在c中基本没有什么改变不了的. 全是内存来回搞, 软件不行硬件~~

 

14) volatile

解释:

声明变量修饰符, 可变的. 当变量前面有这个修饰符. 编译器不再从寄存器中取值, 直接内存读取写入. 保证实时性.

常用在多线程代码中.

演示:

复制代码
//具体轮询器structsrl { mq_t mq;//消息队列pthread_t th;//具体奔跑的线程die_f run;//每个消息都会调用 run(pop())volatileboolloop;//true表示还在继续};
复制代码

以后使用loop的时候, 其它线程修改, 当前线程也能正确获取它的值.

 

15) typedef

解释:

类型重定义修饰符. 重新定义新的类型.

演示:

//声明普通类型typedefvoid*list_t;//声明不完全类型, 头文件中不存在struct treetypedefstructtree * tree_t;

 

16) auto

解释:

变量类型声明符, auto变量存放在动态存储区,随着生命周期{开始 }结束而立即释放.存放在栈上. 

默认变量都是auto的. 基本都是不写, 除非装逼!

演示:

{//生存期开始inthoge =0; autointpiyo =1;//生存期结束}

不要用生命周期结束的变量, 存在各种意外. 

 

17) register

解释:

变量修饰符,只能修饰整形变量.表示希望这个变量存放在CPU的寄存器上.现代编译器在开启优化时候,

能够一定程度上默认启用register寄存器变量.

演示:

复制代码
#include <limits.h>register int i = 0; while (i < INT_MAX) {    ++i; }
复制代码

由于CPU寄存器是有限的, 有时候你哪怕声明的寄存器变量也可能只是普通变量. printf("&i = %p\n", &i) 这种用法是非法.

寄存器变量不能取地址.

 

18) static

解释:

static 用法很广泛. 修饰变量, 表示变量存在于静态区, 基本就是全局区. 生存周期同系统生存周期.

static修饰的变量作用域只能在当前文件范围内. 可以看成上层语言的private. 除了auto就是static.

static修饰函数表示当前函数是私有的,只能在当前文件中使用. 更加详细的看演示部分.

演示:

复制代码
//修饰全局变量, 只对当前文件可见staticint_fd =0;//修饰局部变量, 存储在全局区, 具有记忆功能{staticint_cnt =0; }//修饰函数, 函数只能在当前文件可见staticvoid* _run(void*arg) { ......returnarg; }////C99之后加的static新用法, 编译器优化//static 只能修饰函数第一维,表示数组最小长度, 方便编译器一下取出所有内存进行优化//intsum(inta[static10]) { ... }
复制代码

 

19) extern

解释:

extern 关键字表示声明, 变量声明, 函数声明.  奇葩的用法很多.

演示:

//声明引用全局变量externintg_cnt;//声明引用全局函数externintkill(intsig,intval);

当然有时候extern不写, 对于变量不行会出现重定义. 对于函数是可以缺省写法. 再扯一点

//extern 主动声明, 希望外部可以调用externintkill(intsig,intval);//extern 缺省,不推荐外部调用intkill(intsig,intval);

 

20) break

解释:

结束语句. 主要用于循环的跳转, 只能跳转到当前层级. 也用于switch 语句中, 跳出switch嵌套.

演示:

复制代码
for(;;) {//符合条件跳转if(six ==6)break; }//break 跳出while循环inti =0;while(i <6) {if(i ==3)break; }
复制代码

break用法主要和循环一块使用, 还有do while. 但只能跳转当前层循环. 

 

21) case

解释:

switch 语句中分支语句. 确定走什么分支.

演示:

复制代码
//case 普通用法 和 break成对出现switch((c = *++ptr)) {case'b': *nptr++ ='\b';break;case'f': *nptr++ ='\f';break;case'n': *nptr++ ='\n';break;case'r': *nptr++ ='\r';break;case't': *nptr++ ='\t';break; }
复制代码

多扯一点, 对于case相当于标记点. switch 中值决定case跳转到哪里.再一直往下执行, 遇到break再结束switch嵌套.

 

22) continue

解释:

跳过此次循环. 直接进行条件判断操作. for 和 while 有些局别. for 会执行第三个后面的语句.

演示:

复制代码
//for 循环 continuefor(inti =0; i <20; ++i) {if(i %2==0)continue;//上面continue 调到 ++i -> i < 20 代码块}
复制代码

 

23) default

解释:

switch 分支的默认分支, 假如case都没有进入那就进入default分支. default 可以省略break. c 语法中可行.

演示:

复制代码
uint32_t skynet_queryname(structskynet_context * context,constchar*name) {switch(name[0]) {case':':returnstrtoul(name+1,NULL,16);case'.':returnskynet_handle_findname(name +1);default: skynet_error(context,"Don't support query global name %s",name); }return0; }
复制代码

 

24) do

解释:

do 循环. 先执行循环体, 后再执行条件判断.

演示:

复制代码
register i =0;do{if(i %2==0)continue; printf("i = %d.\n", i); }while(++i <10);
复制代码

do while 循环有时候可以减少一次条件判断. 性能更好, 代码更长.

 

25) else

解释:

else 是 if 的反分支. 具体看演示

演示:

复制代码
#include <stdbool.h>if(true) { puts("你好吗?"); }else{ puts("我们分手吧."); }//附赠个else 语法#ifdefined(__GNUC__)//定义了 __GNUC__ 环境, 就是gcc环境#else#error"NOT __GNUC__, NEED GCC!";#enfif
复制代码

 

26) for

解释:

for 循环其实就是while循环的语法糖. 也有独到的地方.

演示:

复制代码
for(inti =0; i <2; ++i) {if(i ==1)continue;if(i ==2)break; } 等价于下面这个inti =0;while(i <2) {if(i ==1) {++i;continue; }if(i ==2)break;++i; }//for 最好的写法, 在于死循环写法for(;;) {//xxxx}
复制代码

for(;;) {  } 比 while(true) { } 写法好, 有一种不走条件判断的意图, 虽然汇编代码是一样的.

 

27) goto

解释:

goto 是我第二喜欢的关键字.  可以在当前函数内跳转. goto 可以替代所有循环.

演示:

__loop://xxx 死循环用法goto__loop; __exitloop:

还有就是在工程开发中, goto 常用于复制的业务逻辑.

复制代码
if((n = *tar) =='\0')//判断下一个字符goto__err_ext;if(cl % rl){//检测 , 号是个数是否正常__err_ext: SL_WARNING("now csv file is illegal! c = %d, n = %d, cl = %d, rl = %d.", c, n, cl, rl);returnfalse; }
复制代码

 

28) if

解释:

if 分支语句. 用法太多了. 程序语句中分支就是智能.

演示:

if(false) { puts("我想做个好人!"); }

 

29) return

解释:

程序返回语句太多了. 用于函数返回中. 返回void 直接 return;

演示:

#include <stdlib.h>intmain(intargc,char*argv[]) {returnEXIT_SUCCESS; }

 

30) switch

解释:

条件分支语句. 很复杂的if else if 时候可以switch.

演示:

复制代码
#include <unistd.h>do{intrt = write(fd, buf,sizeofbuf)if(rt <0) {switch(errno) {caseEINTERcontinue;default: perror("write error"); } } }while(rt >0);
复制代码

 

31) while

解释:

循环语句, 有do while 和 while 语句两种.

演示:

#define_INT_CNT (10)inti = -1;while(++i <_INT_CNT) {//......}

 

32) sizeof

解释:

这个关键字也称为 sizeof 运算符. 计算变量或类型的字节大小. 这个关键字特别好用!

演示:

sizeof(main) ->x86 上四字节// 获取数组长度,只能是数组类型或""字符串常量,后者包含'\0' #define LEN(arr) (sizeof(arr) / sizeof(*(arr)))

到这里C89保留的关键字基本解释完毕.

 

C99 5个新增关键字

33) _Bool

解释:

bool类型变量, 等价于 unsigned char . 只有0和1.

演示:

#include <stdbool.h>boolflag =true;//或者直接用_Bool flag = !0;

 

34) _Complex

解释:

对于C99 标准定义, 存在 float _Complex, double _Complex, long double _Complex 复数类型. 下面先演示gcc 中关于复数的用法.

演示:

复制代码
#include <math.h>#include<stdio.h>#include<complex.h>////测试 c99 complex 复数//intmain(intargc,char*argv[]) {floatcomplex f = -1.0f+1.0if; printf("The complex number is: %f + %fi\n",crealf(f), cimagf(f));doublecomplex d = csqrt(4.0+4.0i); printf("d = %lf + %lfi\n", creal(d), cimag(d));return0; }
复制代码

其实在复数类型中, gcc标准实现

#definecomplex _Complex

而在VS 中实现具体为

复制代码
#ifndef _C_COMPLEX_T#define_C_COMPLEX_Ttypedefstruct_C_double_complex {double_Val[2]; } _C_double_complex; typedefstruct_C_float_complex {float_Val[2]; } _C_float_complex; typedefstruct_C_ldouble_complex {longdouble_Val[2]; } _C_ldouble_complex;#endiftypedef _C_double_complex _Dcomplex; typedef _C_float_complex _Fcomplex; typedef _C_ldouble_complex _Lcomplex;
复制代码

总的而言, 学习C 最好的平台就是 *nix 平台上使用 Best new GCC. 当然除了科学计算会用到复数, 其它很少.

这里VS 和 GCC实现不一样. 用起来需要注意.

 

35) _Imaginary

解释:

虚数类型. _Complex 复数类型的虚部. 例如 10.0i, 10.8if 等等.  这个关键字在VS 上没有实现. 其实我也觉得没有必要.

和_Complex有重叠.

演示:

这个关键字无法在代码中表示. 系统保留, 我们不能使用.

 

36) inline

解释:

内联函数,从C++中引入的概念. 就是将小函数直接嵌入到代码中. C的代码损耗在于函数的进出栈. 要是可以推荐用内联函数

替代宏. 宏能不用就不用. 函数什么的时候不要加inline 需要加extern, 定义的时候需要加inline.

演示:

复制代码
/** 对json字符串解析返回解析后的结果 * jstr : 待解析的字符串*/externcjson_t cjson_newtstr(tstr_t str); inline cjson_t cjson_newtstr(tstr_t str) { str->len = _cjson_mini(str->str);return_cjson_parse(str->str); }//还有就是和static 一起使用staticinlineint_sconf_acmp(tstr_t tstr,structsconf *rnode) {returnstrcmp(tstr->str, rnode->key); }
复制代码

37) restrict

解释:

这是很装逼的关键字用于编译器优化. 关键字restrict只用于限定指针;该关键字用于告知编译器,

所有修改该指针所指向内容的操作全部都是基于(base on)该指针的,即不存在其它进行修改操作的途径;

这样的后果是帮助编译器进行更好的代码优化,生成更有效率的汇编代码。

演示:

externvoid*mempcpy (void*__restrict __dest,constvoid*__restrict __src, size_t __n) __THROW __nonnull ((1,2));

上面是摘自GCC 的 string.h中. 其实正式用法

//简单演示用法, GCC 和 VS 都是 __restrict 推荐加在 * 后面staticvoid_strlove(char*__restrict dest) {*dest ='\0'; }

Pelles C 编译器可以完整支持 restrict.

 

C11 7个新增关键字

38) _Alignas

解释:

内存对齐的操作符. 需要和_Alignof配合使用, 指定结构的对齐方式.
演示:

复制代码
#ifndef __cplusplus#definealignas _Alignas#definealignof _Alignof#define__alignas_is_defined 1#define__alignof_is_defined 1#endif
复制代码

例如一种用法

复制代码
#include <stdio.h>#include<stdalign.h>structper {intage;doublesecl;charsex; };intmain(intargc,char*argv[]) {charc[100]; alignas(structper)structper * per = (structper *)&c; printf("per = %p, c = %p.\n", per, c);return0; }
复制代码

 

将c 数组以 struct per 对齐方式对齐返回回去.

 

39) _Alignof

解释:

得到类型和变量的对齐方式.
演示:

printf("alignof(struct per) = %zd.\n", alignof(structper));

 

40) _Atomic

解释:

原子操作, 原子锁. gcc 很早就支持. 详细用法可以参照 CAS #/p/18dZQie.html

讲的可以. 
演示:

复制代码
#include <stdio.h>#include<stdatomic.h>intmain(intargc,char*argv[]) { _Atomicinthoge = ATOMIC_VAR_INIT(100);intpiyo = atomic_load(&hoge); printf("piyo = %d.\n", piyo); piyo+=2; atomic_store(&hoge, piyo); printf("hoge = %d.\n", hoge);return0; }
复制代码

具体的执行结果, 你也懂就那样. 原子操作, 对于写出高效代码很重要.

 

41) _Generic

解释:

这个比较叼, C的泛函机制. 高级函数宏. 下面来个老套路用法
演示:

复制代码
#include <math.h>#include<stdio.h>#include<stdlib.h>#defineABS(x) \_Generic((x),int:abs,float:fabsf,double:fabs)(x)////测试 C11 语法//intmain(intargc,char*argv[]) {inta =1, b =2, c =3; _Generic(a+0.1f,int:b,float:c,default:a)++; printf("a = %d, b = %d, c = %d\n", a, b, c); printf("int abs: %d\n", ABS(-12)); printf("float abs: %f\n", ABS(-12.04f)); printf("double abs: %f\n", ABS(-13.09876));returnEXIT_SUCCESS; }
复制代码

宏泛型真的很给力. 宏又能玩上天了.

 

42) _Noreturn

解释:

修饰函数,绝对不会有返回值. _Noreturn 声明的函数不会返回. 引入此新的函数修饰符有两个目的:

  • 消除编译器对没有return的函数的警告. 
  • 允许某种只针对不返回函数的优化.

演示:

_Noreturnvoidsuicide(void) { abort();//Actually, abort is _Noreturn as well}

 

43) _Static_assert

解释:

编译器期间断言, 当 #if #error 搞完毕(预编译)之后, 编译器断言. assert是运行时断言.用的时候看具体的需求.
演示:

_Static_assert(__STDC_VERSION__ >=201112L,"C11 support required");//Guess I don't really need _Static_assert to tell me this :-(

 

44) _Thread_local

解释:

到这里快扯完了, 其实C11标准是个很好的尝试. 为C引入了线程和原子操作. 各种安全特性补充. 可以说C强大了.

但是还远远不够, 因为越来越丑了. C11为C引入了线程 在 头文件<threads.h>中定义.但也允许编译可以不实现.

_Thread_local是新的存储类修饰符, 限定了变量不能在多线程之间共享。
演示:

_Thread_localstaticinti;//Thread local isn't local!

语义上就是线程的私有变量.

预约申请免费试听课

填写下面表单即可预约申请免费试听!怕钱不够?可就业挣钱后再付学费! 怕学不会?助教全程陪读,随时解惑!担心就业?一地学习,可全国推荐就业!

上一篇:学习C语言知识结构表,C语言基础知识点盘点
下一篇:C语言知识结构,C语言学习知识梳理

C语言创建windows窗口实例

C++回调函数是什么?

C++ shared_ptr和动态数组

C语言有哪些关键词,C语言44个关键词大全

Copyright © 2023 Tedu.cn All Rights Reserved 京ICP备08000853号-56 京公网安备 11010802029508号 达内时代科技集团有限公司 版权所有

选择城市和中心
黑龙江省

吉林省

河北省

湖南省

贵州省

云南省

广西省

海南省