c语言最佳实践之关键字

c语言的关键字包括:基本类型、void空类型、条件语句、循环语句、跳转指令、类型修饰符等。其中类型修饰符包括:const、extern、inline、static、volatile、register、restrict。下面按照功能划分,结合代码实例进行介绍。

关键字的功能说明如下表所示:

关键字 功能描述
char 字符类型,1个字节
short 短整型类型,2个字节
int 整型类型,4个字节
long 长整型类型,8个字节
float 浮点类型,4个字节
double 双精度类型,8个字节
void 空类型
auto 自动变量
signed 有符号数
unsigned 无符号数
if 条件语句
else 条件语句的否定分支
switch 开关语句
case 开关语句的某个分支
default 开关语句的其他分支
break 跳出循环体
continue 结束当次循环,继续下一轮
goto 跳转指令
return 子程序地址
for 满足开始与终止条件的循环
while 满足某个条件的循环
do 先执行再循环
struct 结构体
enum 枚举
union 联合体
sizeof 测量数据类型长度
typedef 给变量取别名
const 常量
static 静态变量/方法
extern 外部变量
register 寄存器变量
inline 内联函数
volatile 禁止指令重排序、内存可见
restrict 类型限定符

一、基本类型与特殊类型

1、基本类型

c语言的基本类型包括:int、char、long、float、short、double。

2、void空类型

在c语言中,void为空类型,即可表示任意类型。常用在函数返回值,或void*表示空类型指针。

3、auto自动类型

auto用于自动类型推断,在c++11也有这个关键字。

4、有符号与无符号

有符号用signed表示,比如signed int表示范围-2147483648~2147483647。无符号用unsigned表示,从0开始。

二、条件语句

1、if...else判断

if用于判断某个条件是否成立,如果成立就进入if代码块,否则进入else代码块。

2、switch开关

switch结合case用做开关语句。需要注意的是,最后加上default,否则可能导致进入程序陷阱。示例代码如下:

    switch (num) {
        case 1:
            break;
        case 2:
            break;
        default:
            break;
    }

三、循环语句

1、for

for循环表达式块包括:开始条件、终止条件和自增/自减表达式。示例代码如下:

    for (int i = 0; i < 10; i++) {
        ...
    }

2、while

while循环表达式主要是判断是否满足条件,如果满足条件就继续执行,不满足则跳出循环。示例代码如下:

    while (num < 10) {
        num++;
    }

3、do...while

do/while循环与while循环不同的是,它先执行再判断是否满足条件。示例代码如下:

    do {
        num++;
    } while (num < 10);

四、跳转指令

1、break

break用于跳出循环体,示例代码如下:

    for (int i = 0; i < 10; i++) {
        if (i == 5) {
            break;
        }
    }

2、continue

continue用于跳过当次循环,继续执行下一轮。示例代码如下:

    while (i++ < 10) {
        if (i == 5) {
            continue;
        }
    }

3、goto

goto用于函数内的跳转,即短跳转指令。如果要支持函数外部跳转(长跳转),可以用setjmp。goto的示例代码如下:

void test() {
    int result = read();
    if (result < 0) {
        goto fail;
    }
    printf("result=%d", result);
fail:
    printf("something wrong...");
}

4、return

return用于函数返回。函数执行完成时,或者判断条件不成立时,如果函数有返回值,使用return进行返回。示例代码如下:

int test() {
    int result = read();
    if (result < 0) {
        return -1;
    }
    // something else
    return result;
}

五、结构体与枚举

1、struct结构体

结构体是数据结构的集合,可以存储不同的数据类型。需要注意的是,默认为内存对齐,使用最长的类型长度作为单位。示例代码如下:

struct Person {
    int age;
    char *name;
    float height;
    double weight;
};

2、enum枚举

枚举,顾名思义是枚举出同一类型的可能值。示例代码如下:

enum Fruit {
    APPLE,
    BANANA,
    ORANGE
};

3、union联合体

联合体是几个变量公用一个内存空间,这些变量可以是不同类型不同长度。但是,同一时刻,只能存储一个变量。示例代码如下:

union Type {
    int a;
    short b;
    float c;
    double d;
};

六、类型修饰符

1、const

const为常量修饰符,表示不会再修改的值,存放在常量存储区。可以用于修饰常量,也可以修饰函数参数,或者修饰函数返回值。示例代码如下:

// 常量
const int num = 10;
// 函数参数
void test(char* const val) {

}
// 函数返回值
const char* hello() {
    return "world";
}

2、extern

extern用于声明为外部全局变量,其他源文件也可以调用。首先在file_one.c声明变量:

int global_value = 0;

然后在file_one.h声明为外部变量:

extern int global_value;

 其他源文件file_other.c调用global_value变量:

#include "file_one.h"

void global_test() {
    global_value = 2;
}

3、inline

inline用于声明内联函数,作用是把代码和函数地址放在一起。优点是提高函数调用效率,缺点是增大目标文件的体积。建议使用场景为代码量比较少(10行以内),调用比较频繁的函数。

4、static

在c语言中,static用于声明静态变量、静态方法。存放区域是在静态/全局变量存储区。

5、volatile

volatile用于禁止编译器重排序,并且保证不同线程的内存可见同步。也就是具有可见性、有序性,不具有原子性,用在多线程场景或者底层编码。

6、register

register为寄存器变量,存放在CPU寄存器里,通过CPU寄存器寻址,而不是内存寻址。访问速度快、读写效率高,用于被程序频繁调用的使用场景。需要注意的是,register只能修饰局部变量或者函数形参,不能修饰全局变量或静态变量

7、restrict

restrict为类型限定符,只要是restrict修饰的指针,不能被除该指针以外的其他任何方式修改,无论是直接方式还是间接方式。示例代码如下:

    // 正确写法
    char* restrict str = "hello";
    // 错误写法1
    char restrict *str = "hello";
    // 错误写法2
    restrict char *str = "hello";

七、sizeof与typedef

1、sizeof

sizeof用于测量数据类型长度,比如在malloc申请内存时,或者计算数组长度。示例代码如下:

    // 计算需要申请内存大小
    char* data = (char*) malloc(10 * sizeof(char));
    // 计算数组长度
    int array[] = {1, 2, 3, 4, 5};
    int len = sizeof(array) / sizeof(array[0]);

2、typedef

typedef用于给变量类型取别名。作用是定义平台无关的数据类型,使用简单易懂的名称代替。我们来看看stdint.h头文件的源码:

// signed char取名为__int8_t
typedef signed char __int8_t;
typedef short __int16_t;
typedef int __int32_t;
#if defined(__LP64__)
typedef long __int64_t;
#else
typedef long long __int64_t;
#endif

// __int8_t取名为int8_t,所以int8_t最终指向signed char
typedef __int8_t      int8_t;
typedef __int16_t     int16_t;
typedef __int32_t     int32_t;
typedef __int64_t     int64_t;

八、其他关键字

1、alignof

alignof,用于查询运算类型的对齐要求。在c++中使用_Alignof,代码位于stdalign.h:

#ifndef __cplusplus
#define alignas _Alignas
#define alignof _Alignof
#endif

2、_Atomic

_Atomic用于声明变量为原子类型,包括bool、char、short、int、long等类型。具体可查看头文件stdatomic.h。

3、_Bool

_Bool用于表示布尔类型,0或1。具体可查看头文件stdbool.h,相关源码宏定义如下:

/* Don't define bool, true, and false in C++, except as a GNU extension. */
#ifndef __cplusplus
#define bool _Bool
#define true 1
#define false 0
#elif defined(__GNUC__) && !defined(__STRICT_ANSI__)
/* Define _Bool as a GNU extension. */
#define _Bool bool
#if __cplusplus < 201103L
/* For C++98, define bool, false, true as a GNU extension. */
#define bool  bool
#define false false
#define true  true
#endif
#endif

4、_Static_assert

_Static_assert用于静态断言。相关定义在stdassert.h头文件,宏定义如下:

#if !defined(__cplusplus) && __STDC_VERSION__ >= 201112L
# undef static_assert
# define static_assert _Static_assert
#endif

5、_Thread_local

_Thread_local,用于保存线程相关的变量。需要注意的是,该关键字只能用于修饰全局变量,不能修饰局部变量。示例代码如下:

// 正确用例
_Thread_local int a = 0;

void test() {
    // 错误用例
    _Thread_local int b = 0;
}

猜你喜欢

转载自blog.csdn.net/u011686167/article/details/124307054