公海赌船概述 – C语言老了,概述 – C语言老了

概述 – C语言老了

C宗旨 那多个个重大字,C主旨关键字

概述 – C语言老了

  如今来讲(二〇一七年11月30日) C语言中有 32 + 5 + 7 = 44 个重要字. 具体如下
O(∩_∩)O哈哈~

-> 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   -> signed char 
uint8_t  -> unsigned char

闲聊一点, 程序开采最长遭受的便是自解释问题. 鸡生蛋, 蛋生鸡. 前面再剖析signed 和 unsigned

演示:

#include <stdio.h>

char c;
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 类型.

演示:

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

 

3) int

解释:

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

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

演示:

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

 

4) unsigned

解释:

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

当然当你用这一个修饰变量的时候. 再使用 – 和 — 运算的时候势须求小心

演示:

unsigned int i = 0;          // 正确
unsigned short s = 0;        // 正确
unisgned float f = 0.11f;    // 错误

 

5) long

解释:

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

演示:

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

 

6) float

解释:

  评释变量的时候用! 四字节. 精度是6-7位左右.  详细精度能够看 float与double的限制和精度

演示:

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

 

7) double

解释:

  注解变量的时候用!八字节,精度在15-公斤人左右.部分时候压缩内部存款和储蓄器用float替代.

演示:

double d = 2e13;               // 8字节
long double ld = -0.99;        // x86也是8字节, 不推荐这么用
long long double lld = 99;     // 写法错误, 不支持

 

8) struct

解释:

  定义结构体, 那些尤为重要字用法遍布, 是大头. c
的首要思路正是面向进程编制程序. 撑起面向进程的银元正是构造体.

struct 正是概念结构的事物, 能够看看上边演示

演示:

// 普通结构体定义
struct node {
    int id;
    struct node * next;   
};

struct node node = { 1, NULL };

// 匿名结构定义
struct {
   int id;
   char * name;   
} per = { 2, "王志" };

 

9) union

解释:

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

演示:

// 普通定义
union type {
    char c;
    int i;
    float f;
};

union type t = { .f = 3.33f };

// 匿名定义
union { ... } t = { .... };

// 类型匿名定义
struct cjson {
    struct cjson * next;     // 采用链表结构处理, 放弃二叉树结构, 优化内存
    struct cjson * child;    // type == ( _CJSON_ARRAY or _CJSON_OBJECT ) 那么 child 就不为空

    unsigned char type;      // 数据类型和方式定义, 一个美好的意愿
    char * key;       // json内容那块的 key名称     
    union {
        char * vs;    // type == _CJSON_STRING, 是一个字符串     
        double vd;    // type == _CJSON_NUMBER, 是一个num值, ((int)c->vd) 转成int 或 bool
    };
};

再来一种 union用法, 利用内部存款和储蓄器对齐. 

//12.0 判断是大端序还是小端序,大端序返回true
inline bool
sh_isbig(void) {
    static union {
        unsigned short _s;
        unsigned char _c;
    } _u = { 1 };
    return _u._c == 0;
}

再有相当久以前利用union 达成内部存款和储蓄器字节对齐, 太多了. 各样入眼字用法,
确实相当多, 很意外.

 

10) void

解释:

  这么些是空关键字. 用法比较多. 也是小编最心爱的第一字. 用在函数申明中,
类型定义中.

演示:

// 函数声明
extern void foo();

// 函数参数约束
extern void foo(void);   // ()中加了void表示函数是无参的, 否则是任意的

// 万能类型定义, 指针随便转
void * arg = NULL;

 

11) enum

解释:

  枚举类型, C中枚举类型很简陋. 其实就也正是一种变相的INT宏常量.
推测这恐怕也是 INT宏常量和枚举并存的原因.

演示:

//
// flag_e - 全局操作基本行为返回的枚举, 用于判断返回值状态的状态码
// >= 0 标识 Success状态, < 0 标识 Error状态
//
typedef enum {
    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, 所以大多人家就大概了.

演示:

signed int piyo = 0x1314520;
signed char * str = u8"你好吗";

本来了, 常常没有须求着意加. 会令人嫌麻烦. O(∩_∩)O哈哈~

 

13) const

解释:

  const修饰的变量表示是个不足修改的量. 和常量有一点差异. 能够大约感觉const type val 是个只读的.

演示:

// 声明不可修改的量
const int age = 24;

// 修饰指针
const int * pi = NULL;         // *pi 不能修改指向变量
int * const pt = NULL;         // pt 不能指向新的指针 
const int * const pc = NULL;   // *pc 和 pc 都不能动

实在在c中挑建邺未有啥变动不了的. 全部都以内部存款和储蓄器来回搞, 软件不行硬件~~

 

14) volatile

解释:

  证明变量修饰符, 可变的. 当变量前边有其一修饰符.
编写翻译器不再从存放器中取值, 直接内部存款和储蓄器读取写入. 有限支撑实时性.

常用在二十四线程代码中.

演示:

// 具体轮询器
struct srl {
    mq_t mq;                 // 消息队列
    pthread_t th;            // 具体奔跑的线程
    die_f run;               // 每个消息都会调用 run(pop())
    volatile bool loop;      // true表示还在继续 
};

日后采纳loop的时候, 另外线程修改, 当前线程也能准确获取它的值.

 

15) typedef

解释:

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

演示:

// 声明普通类型
typedef void * list_t;

// 声明不完全类型, 头文件中不存在struct tree
typedef struct tree * tree_t;

 

16) auto

解释:

  变量类型评释符, auto变量寄放在动态存款和储蓄区,随着生命周期{开头}停止而立时释放.寄存在栈上. 

暗中认可变量都以auto的. 基本都是不写, 除非吹嘘!

演示:

{
    // 生存期开始
    int hoge = 0;
    auto int piyo = 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修饰函数表示最近函数是个体的,只好在当下文件中运用.
更加详细的看演示部分.

演示:

// 修饰全局变量, 只对当前文件可见
static int _fd = 0;

// 修饰局部变量, 存储在全局区, 具有记忆功能
{
    static int _cnt = 0;
}

// 修饰函数, 函数只能在当前文件可见
static void * _run(void * arg) {
   ......
   return arg;
}

//
// C99之后加的static新用法, 编译器优化
// static 只能修饰函数第一维,表示数组最小长度, 方便编译器一下取出所有内存进行优化
//
int sum(int a[static 10]) { ... }

 

19) extern

解释:

  extern 关键字表示注明, 变量注解, 函数注脚.  奇葩的用法比较多.

演示:

// 声明引用全局变量
extern int g_cnt;

// 声明引用全局函数
extern int kill(int sig, int val);

本来不时候候extern不写, 对于变量不行会现出重定义. 对于函数是能够缺省写法.
再扯一点

// extern 主动声明, 希望外部可以调用
extern int kill(int sig, int val);

// extern 缺省,不推荐外部调用
int kill(int sig, int val);

 

20) break

解释:

  停止语句. 首要用来循环的跳转, 只可以跳转到当前层级. 也用于switch
语句中, 跳出switch嵌套.

演示:

for(;;) {
   // 符合条件跳转
   if(six == 6)    
       break;
}


// break 跳出while循环
int i = 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
会施行第2个前边的语句.

演示:

// for 循环 continue
for(int i = 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(struct skynet_context * context, const char * name) {
    switch(name[0]) {
    case ':':
        return strtoul(name+1,NULL,16);
    case '.':
        return skynet_handle_findname(name + 1);
    default:
        skynet_error(context, "Don't support query global name %s",name);    
    }
    return 0;
}

 

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 语法
#if defined(__GNUC__)

// 定义了 __GNUC__ 环境, 就是gcc环境

#else

#error "NOT __GNUC__, NEED GCC!";

#enfif

 

26) for

解释:

  for 循环其实正是while循环的语法糖. 也可能有独竖一帜的地方.

演示:

for(int i = 0; i < 2; ++i) {
    if(i == 1)
       continue;
    if(i == 2)
       break;
}

等价于下面这个
int i = 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);
        return false;
    }

 

28) if

解释:

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

演示:

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

 

29) return

解释:

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

演示:

#include <stdlib.h>

int main(int argc, char * argv[]) {

   return EXIT_SUCCESS;
}

 

30) switch

解释: 

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

演示:

#include <unistd.h>

do {
    int rt = write(fd, buf, sizeof buf)
    if(rt < 0) {
       switch(errno) {
       case EINTER
           continue;
       default:
           perror("write error");
       }
    }
} while(rt > 0);

 

31) while

解释:

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

演示:

#define _INT_CNT (10)

int i = -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>

bool flag = 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 复数
//
int main(int argc, char * argv[]) {

    float complex f = -1.0f + 1.0if;
    printf("The complex number is: %f + %fi\n",crealf(f), cimagf(f));

    double complex d = csqrt(4.0 + 4.0i);
    printf("d = %lf + %lfi\n", creal(d), cimag(d));

    return 0;
}

实则在复数类型中, gcc规范兑现

#define complex         _Complex

而在VS 中贯彻具体为

#ifndef _C_COMPLEX_T
    #define _C_COMPLEX_T
    typedef struct _C_double_complex
    {
        double _Val[2];
    } _C_double_complex;

    typedef struct _C_float_complex
    {
        float _Val[2];
    } _C_float_complex;

    typedef struct _C_ldouble_complex
    {
        long double _Val[2];
    } _C_ldouble_complex;
#endif

typedef _C_double_complex  _Dcomplex;
typedef _C_float_complex   _Fcomplex;
typedef _C_ldouble_complex _Lcomplex;

总的来讲, 学习C 最棒的平台正是 *nix 平台上选取 贝斯特 new GCC.
当然除了科学总括会用到复数, 别的相当少.

此间VS 和 GCC完结分裂. 用起来供给注意.

 

35) _Imaginary

解释:

  虚数类型. _Complex 复数类型的虚部. 举个例子 10.0i, 10.8if 等等. 
这么些入眼字在VS 上从未有过兑现. 其实本人也以为无需.

和_Complex有重叠.

演示:

  那几个尤为重要字无法在代码中表示. 系统一保险留, 大家不可能使用.

 

36) inline

解释:

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

代表宏. 宏能不用就不用. 函数什么的时候绝不加inline 须求加extern,
定义的时候须要加inline.

演示:

/*
 * 对json字符串解析返回解析后的结果
 * jstr        : 待解析的字符串
 */
extern cjson_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 一起使用
static inline int _sconf_acmp(tstr_t tstr, struct sconf * rnode) {
    return strcmp(tstr->str, rnode->key);
}

37) restrict

解释:

  那是很装B的基本点字用于编写翻译器优化.
关键字restrict只用于限定指针;该重大字用于告知编写翻译器,

享有修改该指针所指向内容的操作全部是基于(base
on)该指针的,即海市蜃楼别的进行修改操作的路径;

那般的结果是支援编译器实行更加好的代码优化,生成更有作用的汇编代码。

演示:

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

地点是摘自GCC 的 string.h中. 其实正式用法

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

Pelles C 编写翻译器能够完整帮衬 restrict.

 

C11 7个新增添关键字

38) _Alignas

解释:

  内部存款和储蓄器对齐的操作符. 要求和_Alignof合作使用,
钦赐结构的对齐情势.
演示:

#ifndef __cplusplus

#define alignas _Alignas
#define alignof _Alignof

#define __alignas_is_defined 1
#define __alignof_is_defined 1

#endif

诸如一种用法

#include <stdio.h>
#include <stdalign.h>

struct per {
    int age;
    double secl;
    char sex;
};

int main(int argc, char * argv[]) {
    char c[100];
    alignas(struct per) struct per * per = (struct per *)&c;
    printf("per = %p, c = %p.\n", per, c); 

    return 0;
}

 

将c 数组以 struct per 对齐方式对齐再次来到回去.

 

39) _Alignof

解释:

  得到类型和变量的对齐格局.
演示:

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

 

40) _Atomic

解释:

  原子操作, 原子锁. gcc 很已经接济. 详细用法能够参见 CAS
https://sanwen8.cn/p/18dZQie.html

讲的能够.
演示:

#include <stdio.h>
#include <stdatomic.h>

int main(int argc, char * argv[]) {

    _Atomic int hoge = ATOMIC_VAR_INIT(100);
    int piyo = atomic_load(&hoge);  
    printf("piyo = %d.\n", piyo);
    piyo += 2;
    atomic_store(&hoge, piyo);
    printf("hoge = %d.\n", hoge);

    return 0;
}

切实的举办结果, 你也懂就那样. 原子操作, 对于写出高效代码很主要.

 

41) _Generic

解释:

  这些相比较叼, C的泛函机制. 高档函数宏. 上边来个老套路用法
演示:

#include <math.h>
#include <stdio.h>
#include <stdlib.h>

#define ABS(x) \
        _Generic((x), int:abs, float:fabsf, double:fabs)(x)

//
// 测试 C11 语法
//
int main(int argc, char * argv[]) {

        int a = 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));

        return EXIT_SUCCESS;
}

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

   

42) _Noreturn

解释:

  修饰函数,相对不会有再次来到值. _Noreturn 证明的函数不会再次回到.
引入此新的函数修饰符有七个目标:

  • 排除编写翻译器对尚未return的函数的警告. 
  • 同意某种只针对不回去函数的优化.

演示:

_Noreturn void suicide(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_local static int i;
// Thread local isn't local!

语义上正是线程的个体变量.

   

后记 – 我们也不年轻了

  要是有标题接待补充, 关键字当字典用也是好的 哈哈啊

  真正哥们汉 
http://music.163.com/\#/m/song?id=31421394&userid=16529894**
**

  公海赌船 1

  你会心疼吗, 已经心疼了 /(ㄒoㄒ)/~~

 

http://www.bkjia.com/Cyy/1211523.htmlwww.bkjia.comtruehttp://www.bkjia.com/Cyy/1211523.htmlTechArticleC核心 那贰个个第一字,C大旨关键字 概述 – C语言老了
近来来讲(二零一七年6月16日) C语言中有 32 + 5 + 7 = 44 个根本字. 具体如下
O(_)O哈哈~ – C89关键字…

  如今来说(二零一七年十月19日) C语言中有 32 + 5 + 7 = 44 个首要字. 具体如下
O(∩_∩)O哈哈~

-> 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   -> signed char 
uint8_t  -> unsigned char

聊天一点, 程序开垦最常蒙受的正是自解释难点. 鸡生蛋, 蛋生鸡. 前边再剖析signed 和 unsigned

演示:

#include <stdio.h>

char c;
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 类型.

演示:

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

 

3) int

解释:

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

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

演示:

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

 

4) unsigned

解释:

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

本来当您用那几个修饰变量的时候. 再选用 – 和 — 运算的时候自然要小心

演示:

unsigned int i = 0;          // 正确
unsigned short s = 0;        // 正确
unisgned float f = 0.11f;    // 错误

 

5) long

解释:

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

演示:

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

 

6) float

解释:

  注脚变量的时候用! 四字节. 精度是6-7位左右.  详细精度能够看 float与double的限定和精度

演示:

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

 

7) double

解释:

  注明变量的时候用!八字节,精度在15-拾贰人左右.一时压缩内部存款和储蓄器用float代替.

演示:

double d = 2e13;               // 8字节
long double ld = -0.99;        // x86也是8字节, 不推荐这么用
long long double lld = 99;     // 写法错误, 不支持

 

8) struct

解释:

  定义结构体, 那几个首要字用法布满, 是大头. c
的要害思路正是面向进程编制程序. 撑起面向进度的花边正是构造体.

struct 正是概念结构的事物, 能够看看下边演示

演示:

// 普通结构体定义
struct node {
    int id;
    struct node * next;   
};

struct node node = { 1, NULL };

// 匿名结构定义
struct {
   int id;
   char * name;   
} per = { 2, "王志" };

 

9) union

解释:

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

演示:

// 普通定义
union type {
    char c;
    int i;
    float f;
};

union type t = { .f = 3.33f };

// 匿名定义
union { ... } t = { .... };

// 类型匿名定义
struct cjson {
    struct cjson * next;     // 采用链表结构处理, 放弃二叉树结构, 优化内存
    struct cjson * child;    // type == ( _CJSON_ARRAY or _CJSON_OBJECT ) 那么 child 就不为空

    unsigned char type;      // 数据类型和方式定义, 一个美好的意愿
    char * key;       // json内容那块的 key名称     
    union {
        char * vs;    // type == _CJSON_STRING, 是一个字符串     
        double vd;    // type == _CJSON_NUMBER, 是一个num值, ((int)c->vd) 转成int 或 bool
    };
};

再来一种 union用法, 利用内部存款和储蓄器对齐. 

//12.0 判断是大端序还是小端序,大端序返回true
inline bool
sh_isbig(void) {
    static union {
        unsigned short _s;
        unsigned char _c;
    } _u = { 1 };
    return _u._c == 0;
}

再有十分久在此以前利用union 完结内存字节对齐, 太多了. 每种珍爱字用法,
确实相当多, 很意外.

 

10) void

解释:

  这些是空关键字. 用法相当多. 也是本人最欢悦的入眼字. 用在函数证明中,
类型定义中.

演示:

// 函数声明
extern void foo();

// 函数参数约束
extern void foo(void);   // ()中加了void表示函数是无参的, 否则是任意的

// 万能类型定义, 指针随便转
void * arg = NULL;

 

11) enum

解释:

  枚举类型, C中枚举类型很简陋. 其实就也就是一种变相的INT宏常量.
估摸那只怕也是 INT宏常量和枚举并存的原因.

演示:

//
// flag_e - 全局操作基本行为返回的枚举, 用于判断返回值状态的状态码
// >= 0 标识 Success状态, < 0 标识 Error状态
//
typedef enum {
    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, 所以好多人家就大致了.

演示:

signed int piyo = 0x1314520;
signed char * str = u8"你好吗";

本来了, 平时无需着意加. 会令人嫌麻烦. O(∩_∩)O哈哈~

 

13) const

解释:

  const修饰的变量表示是个不得修改的量. 和常量有一点点差异. 能够轻松认为const type val 是个只读的.

演示:

// 声明不可修改的量
const int age = 24;

// 修饰指针
const int * pi = NULL;         // *pi 不能修改指向变量
int * const pt = NULL;         // pt 不能指向新的指针 
const int * const pc = NULL;   // *pc 和 pc 都不能动

事实上在c中着力未有啥样改观不了的. 全都以内部存款和储蓄器来回搞, 软件不行硬件~~

 

14) volatile

解释:

  评释变量修饰符, 可变的. 当变量前边有其一修饰符.
编写翻译器不再从寄放器中取值, 直接内部存储器读取写入. 保障实时性.

常用在二十四线程代码中.

演示:

// 具体轮询器
struct srl {
    mq_t mq;                 // 消息队列
    pthread_t th;            // 具体奔跑的线程
    die_f run;               // 每个消息都会调用 run(pop())
    volatile bool loop;      // true表示还在继续 
};

其后选用loop的时候, 另外线程修改, 当前线程也能准确获取它的值.

 

15) typedef

解释:

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

演示:

// 声明普通类型
typedef void * list_t;

// 声明不完全类型, 头文件中不存在struct tree
typedef struct tree * tree_t;

 

16) auto

解释:

  变量类型注解符, auto变量寄放在动态存款和储蓄区,随着生命周期{起初}结束而及时释放.存放在栈上. 

暗中同意变量都以auto的. 基本都以不写, 除非吹嘘!

演示:

{
    // 生存期开始
    int hoge = 0;
    auto int piyo = 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修饰函数表示前段时间函数是私房的,只可以在近年来文件中使用.
特别详细的看演示部分.

演示:

// 修饰全局变量, 只对当前文件可见
static int _fd = 0;

// 修饰局部变量, 存储在全局区, 具有记忆功能
{
    static int _cnt = 0;
}

// 修饰函数, 函数只能在当前文件可见
static void * _run(void * arg) {
   ......
   return arg;
}

//
// C99之后加的static新用法, 编译器优化
// static 只能修饰函数第一维,表示数组最小长度, 方便编译器一下取出所有内存进行优化
//
int sum(int a[static 10]) { ... }

 

19) extern

解释:

  extern 关键字表示证明, 变量评释, 函数申明.  奇葩的用法比较多.

演示:

// 声明引用全局变量
extern int g_cnt;

// 声明引用全局函数
extern int kill(int sig, int val);

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

// extern 主动声明, 希望外部可以调用
extern int kill(int sig, int val);

// extern 缺省,不推荐外部调用
int kill(int sig, int val);

 

20) break

解释:

  截至语句. 主要用以循环的跳转, 只好跳转到当前层级. 也用于switch
语句中, 跳出switch嵌套.

演示:

for(;;) {
   // 符合条件跳转
   if(six == 6)    
       break;
}


// break 跳出while循环
int i = 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
会推行第4个前面包车型客车语句.

演示:

// for 循环 continue
for(int i = 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(struct skynet_context * context, const char * name) {
    switch(name[0]) {
    case ':':
        return strtoul(name+1,NULL,16);
    case '.':
        return skynet_handle_findname(name + 1);
    default:
        skynet_error(context, "Don't support query global name %s",name);    
    }
    return 0;
}

 

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 语法
#if defined(__GNUC__)

// 定义了 __GNUC__ 环境, 就是gcc环境

#else

#error "NOT __GNUC__, NEED GCC!";

#enfif

 

26) for

解释:

  for 循环其实正是while循环的语法糖. 也是有自成一家的地点.

演示:

for(int i = 0; i < 2; ++i) {
    if(i == 1)
       continue;
    if(i == 2)
       break;
}

等价于下面这个
int i = 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);
        return false;
    }

 

28) if

解释:

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

演示:

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

 

29) return

解释:

  程序重回语句太多了. 用于函数再次回到中. 再次回到void 直接 return;

演示:

#include <stdlib.h>

int main(int argc, char * argv[]) {

   return EXIT_SUCCESS;
}

 

30) switch

解释: 

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

演示:

#include <unistd.h>

do {
    int rt = write(fd, buf, sizeof buf)
    if(rt < 0) {
       switch(errno) {
       case EINTER
           continue;
       default:
           perror("write error");
       }
    }
} while(rt > 0);

 

31) while

解释:

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

演示:

#define _INT_CNT (10)

int i = -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>

bool flag = 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 复数
//
int main(int argc, char * argv[]) {

    float complex f = -1.0f + 1.0if;
    printf("The complex number is: %f + %fi\n",crealf(f), cimagf(f));

    double complex d = csqrt(4.0 + 4.0i);
    printf("d = %lf + %lfi\n", creal(d), cimag(d));

    return 0;
}

实质上在复数类型中, gcc规范兑现

#define complex         _Complex

而在VS 中落实具体为

#ifndef _C_COMPLEX_T
    #define _C_COMPLEX_T
    typedef struct _C_double_complex
    {
        double _Val[2];
    } _C_double_complex;

    typedef struct _C_float_complex
    {
        float _Val[2];
    } _C_float_complex;

    typedef struct _C_ldouble_complex
    {
        long double _Val[2];
    } _C_ldouble_complex;
#endif

typedef _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        : 待解析的字符串
 */
extern cjson_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 一起使用
static inline int _sconf_acmp(tstr_t tstr, struct sconf * rnode) {
    return strcmp(tstr->str, rnode->key);
}

37) restrict

解释:

  那是很说大话的显要字用于编写翻译器优化. 关键字restrict只用于限定指针;该重大字用于告知编写翻译器,

具有修改该指针所指向内容的操作全都是基于(base
on)该指针的,即不设有任何举办改造操作的路线;

与此相类似的后果是补助理编辑译器实行越来越好的代码优化,生成更有效能的汇编代码。

演示:

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

下边是摘自GCC 的 string.h中. 其实正式用法

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

佩尔es C 编写翻译器能够全部协助 restrict.

 

C11 7个新增添关键字

38) _Alignas

解释:

  内部存款和储蓄器对齐的操作符. 须求和_Alignof匹配使用,
钦定结构的对齐方式.
演示:

#ifndef __cplusplus

#define alignas _Alignas
#define alignof _Alignof

#define __alignas_is_defined 1
#define __alignof_is_defined 1

#endif

譬喻一种用法

#include <stdio.h>
#include <stdalign.h>

struct per {
    int age;
    double secl;
    char sex;
};

int main(int argc, char * argv[]) {
    char c[100];
    alignas(struct per) struct per * per = (struct per *)&c;
    printf("per = %p, c = %p.\n", per, c); 

    return 0;
}

 

将c 数组以 struct per 对齐情势对齐再次来到回去.

 

39) _Alignof

解释:

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

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

 

40) _Atomic

解释:

  原子操作, 原子锁. gcc 很已经扶助. 详细用法能够参照 CAS
https://sanwen8.cn/p/18dZQie.html

讲的能够.
演示:

#include <stdio.h>
#include <stdatomic.h>

int main(int argc, char * argv[]) {

    _Atomic int hoge = ATOMIC_VAR_INIT(100);
    int piyo = atomic_load(&hoge);  
    printf("piyo = %d.\n", piyo);
    piyo += 2;
    atomic_store(&hoge, piyo);
    printf("hoge = %d.\n", hoge);

    return 0;
}

切切实实的进行结果, 你也懂就那样. 原子操作, 对于写出高速代码很主要.

 

41) _Generic

解释:

  那一个比较叼, C的泛函机制. 高等函数宏. 上边来个老套路用法
演示:

#include <math.h>
#include <stdio.h>
#include <stdlib.h>

#define ABS(x) \
        _Generic((x), int:abs, float:fabsf, double:fabs)(x)

//
// 测试 C11 语法
//
int main(int argc, char * argv[]) {

        int a = 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));

        return EXIT_SUCCESS;
}

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

   

42) _Noreturn

解释:

  修饰函数,相对不会有再次回到值. _Noreturn 注脚的函数不会重回.
引进此新的函数修饰符有四个指标:

  • 撤消编写翻译器对从未 return的函数的警告. 
  • 同意某种只针对不回来函数的优化.

演示:

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

再扯一点, GCC中等同于 __attribute__((__noreturn__)),
在VC中貌似成效是 __declspec(noreturn).

它不是说函数未有重回值,而是说假令你调了那些函数,它世代不会回来。一些函数是世代不会回去的,

譬喻说 abort也许 exit之类,调用它们就象征甘休程序. 所以
warning就显示不需求.

 

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_local static int i;
// Thread local isn't local!

语义上正是线程的个人变量.

   

后记 – 我们也不青春了

  假使不通常迎接补充, 关键字当字典用也是好的 哈哈啊

  的确男子汉 
http://music.163.com/\#/m/song?id=31421394&userid=16529894**
**

  公海赌船 2

  你会心疼啊, 已经心疼了 /(ㄒoㄒ)/~~

 

相关文章