此文仅参考陈正冲老师所写
C 语言标准定义的 32 个关键字
关键字 意 义
auto 声明自动变量,缺省时编译器一般默认为 auto
int 声明整型变量
double 声明双精度变量
long 声明长整型变量
char 声明字符型变量
float 声明浮点型变量
short 声明短整型变量
signed 声明有符号类型变量
unsigned 声明无符号类型变量
struct 声明结构体变量
union 声明联合数据类型
enum 声明枚举类型
static 声明静态变量
switch 用于开关语句
case 开关语句分支
default 开关语句中的“其他”分支
break 跳出当前循环
register 声明寄存器变量
const 声明只读变量
volatile 说明变量在程序执行中可被隐含地改变
typedef 用以给数据类型取别名(当然还有其他作用)
C99标准
一、定义和声明的区别
int i
extern int i
1.定义的定义:所谓定义就是创建一个对象,并为这个对象分配一块内存给它并取一个名字(变量名) 这个名字一旦和内存匹配起来,他们就不离不弃,这块内存的位置不能被改变,当一个变量或对象在一定区域内(比如函数或者全局)只能被定义一次,多次定义,编译器会提示你重复定义同一个变量或者对象。
2.什么是声明:有两重含义,如下:
第一重含义:告诉编译器,这个名字已经匹配到一块内存上了,下面的代码用到变量或对象是在别的地方定义的。声明可以出现多次。
第二重含义:告诉编译器,我这个名字我先预定了,别的地方再也不能用它来作为变量
名或对象名。比如你在图书馆自习室的某个座位上放了一本书,表明这个座位已经有人预
订,别人再也不允许使用这个座位。其实这个时候你本人并没有坐在这个座位上。这种声
明最典型的例子就是函数参数的声明,例如:
void fun(int i, char c)
二、一些知识点
- auto 编译器在默认的缺省情况下,所有变量都是auto
- register 请求编译器尽可能将变量存在CPU内部而不是通过内存访问以提高效率,是尽可能,因为如果你定义太多此类变量,太累了,根本轮不到。
- 寄存器:
在不考虑CPU高速缓存区情况下,数据从内存里拿出来放到寄存器里,然后CPU再从寄存器里读取数据来处理,处理后同样通过寄存器把数据放到内存里,CPU不直接和内存打交道。为什么要如此呢,主要是考虑速度,寄存器其实就是一块块小的存储空间,只不过其存取内存要比内存开跌多,比在那么大的一块内存里去寻找某个地址上的数据快的多。 - 虽然寄存器的速度非常快,但是使用 register 修饰符也有些限制的:register 变量必须是能被 CPU 寄存器所接受的类型。意味着 register 变量必须是一个单个的值,并且其长度应小于或等于整型的长度。 而且 register 变量可能不存放在内存中,所以不能用取址运算符“&”来获取 register 变量的地址
- static
void example()
{
int flag=0;
flag++;
return flag;
}
第一个程序多次调用结果 0 0 0 0 0 0 0 0
void example()
{
static int flag=0;
flag++;
return flag;
}
第二个程序多次调用结果 0 1 2 3 4 5 6
三、基本数据类型
当你定义了不同的类型的数据的时候同时也确定了你数据的大小,就类似于一个不同的口径模具,喀喀喀,出来了几个不同大小的类型变量供你使用。
四、变量命名的规则
一般规则:
【规则 1-1】命名应当直观且可以拼读,可望文知意,便于记忆和阅读。标识符最好采用英文单词或其组合,不允许使用拼音。程序中的英文单词一般不要太复杂,用词应当准确。
【规则 1-2】命名的长度应当符合“min-length && max-information”原则。C 是一种简洁的语言, 命名也应该是简洁的。例如变量名 MaxVal 就比MaxValueUntilOverflow 好用。标识符的长度一般不要过长,较长的单词可通过去掉“元音”形成缩写。另外,英文词尽量不缩写,特别是非常用专业名词,如果有缩写,在同一系统中对同一单词必须使用相同的表示法,并且注明其意思。
【规则 1-3】当标识符由多个词组成时,每个词的第一个字母大写,其余全部小写。比如:int CurrentVal;这样的名字看起来比较清晰,远比一长串字符好得多。
【规则 1-4】尽量避免名字中出现数字编号,如 Value1,Value2 等,除非逻辑上的确需要编号。比如驱动开发时为管脚命名,非编号名字反而不好
【规则 1-5】对在多个文件之间共同使用的全局变量或函数要加范围限定符(建议使用模块名(缩写)作为范围限定符)。(GUI_ ,etc)标识符的命名规则:
【规则 1-6】标识符名分为两部分:规范标识符前缀(后缀) + 含义标识 。非全局变量可以不用使用范围限定符前缀。
【规则 1-10】程序中不得出现仅靠大小写区分的相似的标识符。
例如:intx, X; 变量 x 与 X 容易混淆
void foo(intx); 函数 foo 与 FOO 容易混淆
void FOO(floatx);
这里还有一个要特别注意的就是 1(数字 1)和 l(小写字母 l)之间,0(数字 0)和 o
(小写字母 o)之间的区别。这两对真是很难区分的
【规则 1-11】一个函数名禁止被用于其它之处。
例如:
#include "c_standards.h"
void foo(intp_1)
{
intx = p_1;
}
void static_p(void)
{
intfoo = 1u;
}
【规则 1-12】所有宏定义、枚举常数、只读变量全用大写字母命名,用下划线分割单词。
例如:
const int MAX_LENGTH = 100; //这不是常量,而是一个只读变量,具体请往后看
#define FILE_PATH “/usr/tmp”
【规则 1-13】考虑到习惯性问题,局部变量中可采用通用的命名方式,仅限于 n、i、j 等作
为循环变量使用。
一定不要写出如下这样的代码:
int p;
char i;
int c;
char * a;
一般来说习惯上用 n,m,i,j,k 等表示 int 类型的变量;c,ch 等表示字符类型变量;a 等表
示数组;p 等表示指针。当然这仅仅是一般习惯,除了 i,j,k 等可以用来表示循环变量外,别
的字符变量名尽量不要使用。
【规则 1-14】定义变量的同时千万千万别忘了初始化。定义变量时编译器并不一定清空了
这块内存,它的值可能是无效的数据。
这个问题在内存管理那章有非常详细的讨论,请参看。
【规则 1-15】不同类型数据之间的运算要注意精度扩展问题,一般低精度数据将向高精度
数据扩展。
tips
- case 后面只能是整型或字符型的常量或常量表达式(想想字符型数据在内存里
是怎么存的)。 - break 关键字很重要,表示终止 本层循环。现在这个例子只有一层循环,当代码执行到
break 时,循环便终止。如果把 break 换成 continue 会是什么样子呢?continue 表示终止 本次(本轮)循环。当代码执行到 continue 时,本轮循环终止,进入下一轮循环。while(1)也有写成 while(true) 或者while(1==1) 或者 while((bool) 1)等形式的,效果一样。do-while 循环:先执行 do 后面的代码,然后再判断 while 后面括号里的值,如果为真,循环开始;否则,循环不开始。其用法与 while 循环没有区别,但相对较少用。for 循环:for 循环可以很容易的控制循环次数,多用于事先知道循环次数的情况下。 - 在 C 语言中,const 修饰的 Max 仍然是变量,只不过是只读属性罢了;而在 C++里,扩展了 const 的含义,这里就不讨论了。注意:const 修饰的只读变量必须在定义的同时初始化
- 编译器通常不为普通 const 只读变量分配存储空间,而是将它们保存在符号表中,这使得它成为一个编译期间的值,没有了存储与读内存的操作,使得它的效率也很高。
例如:
#define M 3 //宏常量
constintN=5; //此时并未将 N 放入内存中
…
inti=N; //此时为 N 分配内存,以后不再分配!
intI=M; //预编译期间进行宏替换,分配内存
intj=N; //没有内存分配
intJ=M; //再进行宏替换,又一次分配内存!
const 定义的只读变量从汇编的角度来看,只是给出了对应的内存地址,而不是象#define一样给出的是立即数,所以,const 定义的只读变量在程序运行过程中只有一份拷贝(因为它是全局的只读变量,存放在静态区),而#define 定义的宏常量在内存中有若干个拷贝。#define 宏是在预编译阶段进行替换,而 const 修饰的只读变量是在编译的时候确定其值。#define 宏没有类型,而 const 修饰的只读变量具有特定的类型。