c语言关键字总结

目录

 1.register关键字

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

 3.基本数据类型

 4.bool

 5.float 变量与"零值"进行比较

 6.switch,case组合

 7.void关键字

 8.return关键字

 9.const关键字

10.volatile关键字

11.void关键字

12.union,enum关键字

13.typedef,define关键字




补充内容

那么启动程序的本质是什么呢?将程序数据,加载到内存中,让计算机运行!程序在未运行时,在硬盘中,加载到内存中,速度较快

 什么是变量(是什么)——在内存中开辟特定大小的空间,用来保存数据

变量定义的本质——我们现在已知: 1. 程序运行,需要加载到内存中 2. 程序计算,需要使用变量 那么,定义变量的本质:在内存中开辟一块空间,用来保存数据。(为何一定是内存:因为定义变量,也是程序逻辑的一部 分,程序已经被加载到内存。

变量的分类——局部变量:包含在代码块中的变量叫做局部变量。局部变量具有临时性。进入代码块,自动形成局部变量,退出代码块自动 释放。[网上很多说函数中的变量是局部变量,不能说错,但说法是不准确的] 全局变量:在所有函数外定义的变量,叫做全局变量。全局变量具有全局性。

作用域概念:指的是该变量的可以被正常访问的代码区域

局部变量:只在本代码块内有效。全局变量:整个程序运行期间,都有效。

生命周期概念:指的是该变量从定义到被释放的时间范围,所谓的释放,指的是曾经开辟的空间”被释放“

局部变量: 进入代码块,形成局部变量[开辟空间],退出代码块,"释放"局部变量

全局变量: 定义完成之后,程序运行的整个生命周期内,该变量一直都有效

1.register关键字

 尽量将所修饰变量,放入CPU寄存区中,从而达到提高效率的目的

register修饰的变量,不能取地址(因为已经放在寄存区中了嘛,地址是内存相关的概念)

那么什么样的变量,可以采用register呢?

1. 局部的(全局会导致CPU寄存器被长时间占用) 比特就业课 2. 不会被写入的(写入就需要写回内存,后续还要读取检测的话,register的意义在哪呢?) 3. 高频被读取的(提高效率所在) 4. 如果要使用,请不要大量使用,因为寄存器数量有限

意见:该关键字,不用管,因为现在的编译器,已经很智能了,能够进行比人更好的代码优化。 早期编译器需要人为指定register,来进行手动优化,现在不需要了。

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

1. 修饰全局变量,该全局变量只能在本文件内被使用,不能被其它外部文件直接访问。

2.static修饰局部变量,变量的生命周期变成全局周期。(作用域不变)

static修饰变量,它们都在内存的静态区。

3.static可修饰函数,该函数只能在本文件内被使用,不能被其它外部文件直接访问。

3.基本数据类型

 4.bool

C语言有没有bool类型? c99之前,主要是c90是没有的,目前大部分书,都是认为没有的。因为书,一般都要落后于行业。 但是c99引入了_Bool类型(你没有看错,_Bool就是一个类型,不过在新增头文件stdbool.h中,被重新用宏写成了 bool,为了保证C/C++兼容性)。

//测试代码1
#include <stdio.h>
#include <stdbool.h> //没有这个头文件会报错,使用新特性一定要加上
#include <windows.h>
int main()
{
bool ret = false;
ret = true;
printf("%d\n", sizeof(ret)); //vs2013 和 Linux中都是1
system("pause");
return 0;
}
源码:#define bool _Bool //c99中是一个关键字哦,后续可以使用bool
#define false 0 //假
#define true 1 //真


int main()
{
//在vs中,光标选中BOOL,单击右键,可以看到转到定义,就能看到BOOL是什么
BOOL ret = FALSE;
ret = TRUE;
printf("%d\n", sizeof(ret)); //输出结果是4,因为在源代码中,是这么定义的:typedef int BOOL;
system("pause");
return 0;
}
微软?强烈不推荐,因为好的习惯是:一定要保证代码的跨平台性,微软定义的专属类型,其他平台不支持。

5.float 变量与"零值"进行比较

因为精度损失问题,两个浮点数,绝对不能使用==进行相等比较.

 //伪代码-简洁版 if(fabs(x-y) < 精度){ //fabs是浮点数求绝对值 //TODO }

#include //使用下面两个精度,需要包含该头文件

DBL_EPSILON //double 最小精度

FLT_EPSILON //float 最小精度

 6.switch,case组合

case之后,如果没有break,则会依次执行后续有效语句,直到碰到break

default可以出现在switch内的任何部分,尽管如此,我们依旧强烈推荐default应该放在case语句的最后

 7.void关键字

void是否可以定义变 

 int main()

{

void a;

system("pause");

return 0;

}

//在vs2013和Centos 7,gcc 4.8.5下都不能编译通过

定义变量的本质:开辟空间 而void作为空类型,理论上是不应该开辟空间的,即使开了空间,也仅仅作为一个占位符看待 所以,既然无法开辟空间,那么也就无法作为正常变量使用,既然无法使用,编译器干脆不让他定义变量。 在vs2013中,sizeof(void)=0 在Linux中,sizeof(void)=1(但编译器依旧理解成,无法定义变量)

1.修饰函数返回值和参数

/如果自定义函数,或者库函数不需要返回值,那么就可以写成void 。那么问题来了,可以不写吗?不可以,自定义函数的默认返回值是int(这个现场验证) 。所以,没有返回值,如果不写void,会让阅读你代码的人产生误解:他是忘了写,还是想默认int?

int test()
{return 1;
}
int test(void)
{return 1;
}
int main()
{
printf("%d\n", test1(10)); //依旧传入参数,编译器不会告警或者报错
printf("%d\n", test2(10)); //依旧传入参数,编译器会告警(vs)或者报错(gcc)
system("pause");
return 0;
}

如果一个函数没有参数,将参数列表设置成void,是一个不错的习惯,因为可以将错误明确提前发现

 

 8.return关键字

 调用函数,形成栈帧,函数返回,释放栈帧。临时变量为什么具有临时性,栈帧结构在函数调用完,需要被释放

 9.const关键字

1.const修饰变量。 让编译器进行直接修改式检查 ,告诉其他程序员(正在改你代码或者阅读你代码的)这个变量后面不要改哦。也属于一种“自描述”含义

2.const修饰数组

3.const修饰指针(const int *p,int *const p)

4.修饰函数参数(防止使用者的一些无意的或错误的修改,任何函数参数都要形成新的地址)

5.修饰函数返回值(const 修饰符也可以修饰函数的返回值,返回值不可被改变)

在另一连接文件中引用 const 只读变量: extern const int i; //正确的声明

10.volatile关键字

volatile 用它修饰的变量表示可以被某些编译器 未知的因素更改,比如操作系统、硬件或者其它线程等。遇到这个关键字声明的变量,编 译器对访问该变量的代码就不再进行优化,从而可以提供对特殊地址的稳定访问。忽略编译器的优化,保持内存可见性。

补充:——const要求你不要进行写入就可以。volatile意思是你读取的时候,每次都要从内存读。 两者并不冲突。 虽然volatile就叫做易变关键字,但这里仅仅是描述它修饰的变量可能会变化,要编译器注意,并不是它要求对应变量必须 变化!这点要特别注意。

 11.void关键字

void不可以定义变量,在vs2013和Centos 7,gcc 4.8.5下都不能编译通过

解释:定义变量的本质:开辟空间 而void作为空类型,理论上是不应该开辟空间的,即使开了空间,也仅仅作为一个占位符看待 所以,既然无法开辟空间,那么也就无法作为正常变量使用,既然无法使用,编译器干脆不让他定义变量。 在vs2013中,sizeof(void)=0 在Linux中,sizeof(void)=1(但编译器依旧理解成,无法定义变量)

void修饰函数返回值和参数

//如果自定义函数,或者库函数不需要返回值,那么就可以写成void

//那么问题来了,可以不写吗?不可以,自定义函数的默认返回值是int(这个现场验证)

//所以,没有返回值,如果不写void,会让阅读你代码的人产生误解:他是忘了写,还是想默认int


//void 作为函数参数
//如果一个函数没有参数,我们可以不写, 如test1()
#include <stdio.h>
#include <windows.h>
int test1() //函数默认不需要参数
{
return 1;
}
int test2(void) //明确函数不需要参数
{
return 1;
}
int main()
{
printf("%d\n", test1(10)); //依旧传入参数,编译器不会告警或者报错
printf("%d\n", test2(10)); //依旧传入参数,编译器会告警(vs)或者报错(gcc)
system("pause");
return 0;
}

//结论:如果一个函数没有参数,将参数列表设置成void,是一个不错的习惯,因为可以将错误明确提前发现

void指针

#include <windows.h>
int main()
{
void *p = NULL; //可以
system("pause");
return 0;
}
//为什么void*可以呢?因为void*是指针,是指针,空间大小就能明确出来

void* 能够接受任意指针类型

void * 定义的指针变量可以进行运算操作吗?


//在vs2013中
#include <stdio.h>
#include <windows.h>
int main()
{
void *p = NULL;
p++; //报错
p += 1; //报错
system("pause");
return 0;
}
//在gcc4.8.5中
#include <stdio.h>
int main()
{
void *p = NULL; //NULL在数值层面,就是0
p++; //能通过
printf("%d\n", p); //输出1
p += 1; //能通过
printf("%d\n", p); //输出2
return 0;
}
//为什么在不同的平台下,编译器会表现出不同的现象呢
根本原因是因为使用的C标准扩展的问题。

12.union,enum关键字

1.

联合体内,所有成员的起始地址都是一样的

union un{

int i;
char a[4];

}*p,u;
int main()
{
p=&a;
p.a[0]=0x39;
p.a[1]=0x40;
p.a[2]=0x41;
p.q[3]=0x42;
printf("0x%x",p.i);

}
0x39404142

 

 2.

1),#define 宏常量是在预编译阶段进行简单替换。枚举常量则是在编译的时候确定其值。

2),一般在编译器里,可以调试枚举常量,但是不能调试宏常量。

3),枚举可以一次定义大量相关的常量,而#define 宏一次只能定义一个。

 13.typedef,define关键字

类型重命名,并不是文本替换,而define为文本替换

//1. 对一般类型进行重命名

//2. 对结构体类型进行重命名

//3. 对指针进行重命名

//4. 对复杂结构进行重命名(数组类型为例,先不要搞那么复杂) 

 举例1:

typedef int* p=int_p;

#define ptr_p int*

int main()

{  int_p a,b;      //此时两个变量的类型都为int*

ptr_p a,b,c;     //a类型为int*,b,c类型为int
}

举例2:

#define IN int

typedef int IM;

int main()

{unsigned IN a;

unsigned IM b;//报错
}

5个存储类型关键字

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值