hylerrix / university

:mortar_board: my university code & article collection: create & share, thought & works
Creative Commons Attribution Share Alike 4.0 International
45 stars 10 forks source link

[A14]C 语言 32 个关键字 GET 进行曲 #24

Open hylerrix opened 7 years ago

hylerrix commented 7 years ago

C 语言标准定义的 32 个关键字有什么,分别怎么用,用的时候需要注意到什么,便是这篇文章所要告诉的一切。内容较长,先上本篇文章结构思维导图。文章结尾处有 32 个关键字附录。

- 修饰类 -

- 1. extern -- 最会带帽子的关键字 -

int i;    // 变量的定义
extern int i;    // 变量的声明

void fun(int i, char c);    // 函数的声明
void fun(int i, char c) {}    // 函数的定义

- 2. auto -

- 3. register -- 最快的关键字 -

3.1 寄存器

为什么寄存器比内存快?

CPU Registers 即为寄存器

3.2 使用 register 修饰符的注意点

- 4. static -- 最名不符实的关键字 -

关键字 static 有着不寻常的历史。起初,在 C 中引入关键字 static 是为了表示退出一个块后仍然存在的局部变量。随后,static 在 C 中有了第二种含义:用来表示不能被其它文件访问的全局变量和函数。为了避免引入新的关键字,所以仍使用 static 关键字来表示这第二种含义。

4.1 修饰变量

4.2 修饰函数

- 5. const 关键字 -

5.1 const 修饰的只读变量

5.2 节省空间,避免不必要的内存分配,同时 高效率

5.3 修饰一般变量

int const i=2;    // 正确
const int j=2;    // 正确

5.4 修饰数组

int const a[5]={1, 2, 3, 4, 5};    // 正确
const int b[5]={1, 2, 3, 4, 5};    // 正确

5.5 修饰指针

const int *p;    // p 可变,p 指向的对象不可变
int const *p;    // p 可变,p 指向的对象不可变
int *const p;    // p 不可变, p 指向的对象可变
const int *const p;    // 指针 p 和 p 指向的对象都不可变

5.6 修饰函数的参数

void Fun(const int i);

5.7 修饰函数的返回值

const int Fun (void);
extern const int i;    // 正确的声明
extern const int j=10;    // 错误!只读变量的值不能改变。

- 6. signed、unsigned 关键字 -

signed int i;
unsigned int love;
signed int u;

「C语言」原码反码补码与位运算

- 数据类型 -

- 7. 数据类型 -

7.1 数据类型与“模子”

「C语言」数据类型及混合运算与类型转换

7.2 变量的命名规则

「C语言」常量和变量的表示、应用和变量命名规则

- 8. void 关键字 -

8.1 void 修饰函数返回值和参数

8.2 void 指针

void * pvoid;pvoid++;    // ANSI:错误
pvoid += 1;    // ANSI:错误

但是大名鼎鼎的 GNU(GNU's Not Unix 的递归缩写)则不这么认定,它指定 void 的算法操作与 char 一致。因此下列语句在 GNU 编译器中皆正确:

pvoid++;    // GNU:正确
pvoid += 1;    // GNU:正确

因此,为了兼容两大标准, 高程序的可移植性,我们可以这样编写实现同样功能的代码:

void * pvoid;(char *)pvoid++;    // ANSI:正确;GNU:正确(char *)
pvoid += 1;    // ANSI:错误;GNU:正确
void * memcpy(void *dest, const void *src, size_t len);
void * memset ( void * buffer, int c, size_t num );

8.3 void 不能代表一个真实的变量

void a;    // 错误
function(void a);    // 错误

- 9. struct 关键字 -

9.1 空结构体有多大

struct student{

} stu;

9.2 柔性数组

typedef struct st_type {
    int i;
    int a[];
} type_a;
type_a *p = (type_a*)malloc(sizeof(type_a)+100*sizeof(int));

9.3 struct 和 class 的区别

- 10. union 关键字 -

union StateMachine
{
    char character;
    int number;
    char *str;
    double exp;
};

10.1 大小端模式对 union 类型数据的影响

union {
    int i;
    char a[2];
} *p, u;

p = &u;
p->a[0] = 0x39;
p->a[1] = 0x38;

- 11. enum 关键字 -

11.1 枚举类型的使用方法

enum enum_type_name
{
    ENUM_CONST_1,
    ENUM_CONST_2,
    ...
    ENUM_CONST_n
} enum_variable_name;

11.2 枚举与 #define 宏的区别

- 选择分支 -

- 12. If else 组合 -

12.1 bool 变量与“零值”进行比较

bool bTestFlag = FALSE;    // 一般要初始化为 FALSE
if(bTestFlag == 0);    // 不好。容易被误解为整型变量
if(bTestFlag == TRUE);    // 不好。TRUE的值不都为1。
if(bTestFlag);    // 推荐

12.2 float 变量与“零值”进行比较

float fTestVal = 0.0;
if(fTestVal == 0.0);    // 不好。
if((fTestVal >= -EPSINON) && (fTestVal <= EPSINON));    // 推荐。EPSINON 为定义好的精度。在该范围内则认为为零值

12.3 指针变量与“零值”进行比较

if(p == 0);    // 尽管 NULL 值为0,容易引起 p 是整型的误会。
if(p);    // 容易引起 p 是 bool 型的误会
if(NULL == p);    // 推荐。且 NULL 要写在左值避免 p = NULL; 的错误赋值。

12.4 else 到底与哪个 if 配对呢?

if(0 == x)
if(0 == y) error();
else {
//program code
}    // 这段代码容易引起误会
for (initialization; condition; update) 
{
    // 推荐风格
}

for(initialization; condition; update){
    // 不推荐风格
}

12.5 if 语句后面的分号

if(NULL != p);
    fun();
NULL;

- 13. switch case 关键字 -

13.1 case 关键字后面的值的要求

13.2 case语句的排列顺序

13.3 使用 case 语句的其他注意事项

- 14. goto 关键字 -

struct student *p = NULL;
...
goto state;
p = (struct student *)malloc(...);    // 被 goto 跳过,没有初始化
...
state:    // 使用 p 指向的内存里的值的代码⋯

- 循环分支 -

- 15. do while for 关键字 -

15.1 break 与 continue 的区别

15.2 循环语句的注意点

- 其他 -

- 16. sizeof -- 最冤枉的关键字 -

sizeof(int);    // 正确
sizeof int;    // 错误
int a[10];
sizeof a;    // 正确
sizeof(a);    // 正确

- 17. typedef -- 伟大的缝纫师 -

17.1 历史的误会----也许应该是 typerename

typedef struct student {
//code
} Stu_st, *Stu_pst;
struct student stu1;    // (1)
Stu_st stu1;    // (2)
struct student *stu2;    // (3)
Stu_pst stu2;    // (4)
Stu_st *stu2;    // (5)

17.2 typedef 与#define 的区别

#define INT32 int
unsigned INT32 i = 10;    // 正确
typedef int INT32;
unsigned INT32 j = 10;    // 错误

从这段代码可以看出 typedef 取的别名不支持这种类型扩展。

#define PCHAR char*
PCHAR p3,p4;    // 等价于 char *p3;char p4;
typedef char* pchar;
pchar p1,p2;    // 等价于 char *p1;char *p2;

从这段代码又可以看出 #define 仅仅是简单的替换,并无法代表一个数据类型。

- 18. volatile -- 最易变的关键字 -

18.1 编译器优化

int i=10;
int j = i;    // (1)语句
int k = i;    // (2)语句

18.2 volatile 关键字防止编译器优化

volatile int i=10;
int j = i;    // (3)语句
int k = i;    // (4)语句

- 19. return 关键字 -

附录:C 语言标准定义的 32 个关键字

关键字 意 义
auto 声明自动变量,缺省时编译器一般默认为 auto
int 声明整型变量
double 声明双精度变量
long 声明长整型变量
char 声明字符型变量
float 声明浮点型变量
short 声明短整型变量
signed 声明有符号类型变量
unsigned 声明无符号类型变量
struct 声明结构体变量
union 声明联合数据类型
enum 声明枚举类型
static 声明静态变量
switch 用于开关语句
case 开关语句分支
default 开关语句中的“其他”分支
break 跳出当前循环
register 声明寄存器变量
const 声明只读变量
volatile 说明变量在程序执行中可被隐含地改变
typedef 用以给数据类型取别名(当然还有其他作用)
extern 声明变量是在其他文件正声明(也可以看做是引用变量)
return 子程序返回语句(可以带参数,也可不带参数)
void 声明函数无返回值或无参数,声明空类型指针
continue 结束当前循环,开始下一轮循环
do 循环语句的循环体
while 循环语句的循环条件
if 条件语句
else 条件语句否定分支(与 if 连用)
for 一种循环语句(可意会不可言传)
goto 无条件跳转语句
sizeof 计算对象所占内存空间大小

写在最后

这篇文章灵感和素材均来源自《C 语言深度解剖》这本书,感谢作者对 C 语言的独特见解,如有需要,欢迎购买实体书籍支持作者。