C语⾔——关键字(C语⾔标准定义的32个关键字:auto、
register、static、。。。
C语⾔标准定义的32个关键字:(列出每个关键字的意义)
关键字 意 义
auto 声明⾃动变量,缺省时编译器⼀般默认为 auto
int 声明整型变量
double 声明双精度变量
long 声明长整型变量
char 声明字符型变量
register的名词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 计算对象所占内存空间⼤⼩
1.1,最宽恒⼤量的关键字----auto
auto:它很宽恒⼤量的,你就当它不存在吧。编译器在默认的缺省情况下,所有变量
都是 auto 的。
1.2,最快的关键字---- register
register:这个关键字请求编译器尽可能的将变量存在 CPU 内部寄存器中⽽不是通过内
存寻址访问以提⾼效率。注意是尽可能,不是绝对。你想想,⼀个 CPU 的寄存器也就那么
⼏个或⼏⼗个,你要是定义了很多很多 register 变量,它累死也可能不能全部把这些变量放
⼊寄存器吧,轮也可能轮不到你。
使⽤ register 修饰符的注意点:虽然寄存器的速度⾮常快,但是使⽤ register 修饰符也有些限制的: register 变量必须是能被 CPU 寄存器所接受的类型。意味着 register 变量必须是⼀个单个的值,并且其长度应⼩
于或等于整型的长度。 ⽽且 register 变量可能不存放在内存中, 所以不能⽤取址运算符“ &”
来获取 register 变量的地址。
1.3,最名不符实的关键字----static
不要误以为关键字 static 很安静,其实它⼀点也不安静。这个关键字在 C 语⾔⾥主要有
两个作⽤, C++对它进⾏了扩展
1.3.1,修饰变量
第⼀个作⽤:修饰变量。变量⼜分为局部和全局变量,但它们都存在内存的静态区。
静态全局变量,作⽤域仅限于变量被定义的⽂件中,其他⽂件即使⽤ extern 声明也没法
使⽤他。准确地说作⽤域是从定义之处开始,到⽂件结尾处结束,在定义之处前⾯的那些
代码⾏也不能使⽤它。想要使⽤就得在前⾯再加 extern ***。恶⼼吧?要想不恶⼼,很简单,
直接在⽂件顶端定义不就得了。
静态局部变量,在函数体⾥⾯定义的,就只能在这个函数⾥⽤了,同⼀个⽂档中的其他
函数也⽤不了。由于被 static 修饰的变量总是存在内存的静态区,所以即使这个函数运⾏结
束,这个静态变量的值还是不会被销毁,函数下次使⽤时仍然能⽤到这个值。
static int j;
void fun1( void)
{
static inti = 0;
i ++;
}
void fun2( void)
{
j = 0;
j++;
}
intmain()
{
for(k=0; k<10; k++)
{
fun1();
fun2();
}
return 0;
}
i 和 j 的值分别是什么,为什么?(i会从1累加到10,就)
1.3.2,修饰函数
第⼆个作⽤:修饰函数。函数前加 static 使得函数成为静态函数。但此处“static”的含义
不是指存储⽅式,⽽是指对函数的作⽤域仅局限于本⽂件(所以⼜称内部函数)。使⽤内部函
数的好处是:不同的⼈编写不同的函数时,不⽤担⼼⾃⼰定义的函数,是否会与其它⽂件
中的函数同名。
关键字 static 有着不寻常的历史。起初,在 C 中引⼊关键字 static 是为了表⽰退出⼀个
块后仍然存在的局部变量。随后, static 在 C 中有了第⼆种含义:⽤来表⽰不能被其它⽂件
访问的全局变量和函数。为了避免引⼊新的关键字,所以仍使⽤ static 关键字来表⽰这第⼆
种含义。
当然, C++⾥对 static 赋予了第三个作⽤,这⾥先不讨论,有兴趣的可以相关资料研
究。
1.4,基本数据类型----short、int、 long、char、float、double
C 语⾔包含的数据类型如下图所⽰:
⼀般来说习惯上⽤ n,m,i,j,k 等表⽰ int 类型的变量; c, ch 等表⽰字符类型变量; a 等表
⽰数组; p 等表⽰指针。当然这仅仅是⼀般习惯,除了 i,j,k 等可以⽤来表⽰循环变量外,别
的字符变量名尽量不要使⽤。
1.5,最冤枉的关键字----sizeof
sizeof 是关键字不是函数,其实就算不知道它是否为 32 个关键字之⼀时,我们也可以
借助编译器确定它的⾝份。看下⾯的例⼦:
int i=0;
A),sizeof(int); B), sizeof(i); C), sizeof int; D), sizeof i;
毫⽆疑问, 32 位系统下 A), B)的值为 4。那 C)的呢? D)的呢?
在 32 位系统下,通过 Visual C++6.0 或任意⼀编译器调试,我们发现 D)的结果也为 4。
咦? sizeof 后⾯的括号呢?没有括号居然也⾏,那想想,函数名后⾯没有括号⾏吗?由此轻
易得出 sizeof 绝⾮函数。
好,再看 C)。编译器怎么怎么提⽰出错呢?不是说 sizeof 是个关键字,其后⾯的括号
可以没有么?那你想想 sizeof int 表⽰什么啊? int 前⾯加⼀个关键字?类型扩展?明显不
正确,我们可以在 int 前加 unsigned, const 等关键字但不能加 sizeof。好,记住: sizeof 在计算变量所占空间⼤⼩时,括号可以省略,⽽计算类型(模⼦)⼤⼩时不能省略。⼀般情况下,
咱也别偷这个懒,乖乖的写上括号,继续装作⼀个“函数”,做⼀个“披着函数⽪的关键字”。做我的关键字,让⼈家认为是函数去吧。
1.6,signed、unsigned 关键字
我们知道计算机底层只认识 0、 1.任何数据到了底层都会变计算转换成 0、 1.那负数怎么
存储呢?肯定这个“ -”号是⽆法存⼊内存的,怎么办?很好办,做个标记。把基本数据类
型的最⾼位腾出来,⽤来存符号,同时约定如下:最⾼位如果是 1,表明这个数是负数,其
值为除最⾼位以外的剩余位的值添上这个“ -”号;如果最⾼位是 0,表明这个数是正数,
其值为除最⾼位以外的剩余位的值。
1.7 break 与 continue 的区别
break 关键字很重要,表⽰终⽌本层循环。现在这个例⼦只有⼀层循环,当代码执⾏到
break 时,循环便终⽌。
如果把 break 换成 continue 会是什么样⼦呢? continue 表⽰终⽌本次(本轮) 循环。当
代码执⾏到 continue 时,本轮循环终⽌,进⼊下⼀轮循环。
while( 1)也有写成 while(true) 或者 while(1==1) 或者 while((bool) 1)等形式的,效果⼀
样。
do-while 循环:先执⾏ do 后⾯的代码,然后再判断 while 后⾯括号⾥的值,如果为真,
循环开始;否则,循环不开始。其⽤法与 while 循环没有区别,但相对较少⽤。
for 循环: for 循环可以很容易的控制循环次数,多⽤于事先知道循环次数的情况下。
1.8,void 关键字
void 有什么好讲的呢?如果你认为没有,那就没有;但如果你认为有,那就真的有。有点像“⾊即是空,空即是⾊”。void 真正发挥的作⽤在于:
(1) 对函数返回的限定;  (2) 对函数参数的限定
众所周知, 如果指针 p1 和 p2 的类型相同, 那么我们可以直接在 p1 和 p2 间互相赋值;
如果 p1 和 p2 指向不同的数据类型,则必须使⽤强制类型转换运算符把赋值运算符右边的
指针类型转换为左边指针的类型。
例如:
float *p1;
int *p2;
p1 = p2;
其中 p1 = p2 语句会编译出错,提⽰“'=' : cannot convertfrom 'int *' to 'float *'”,必须改为:
p1 = (float *)p2;
⽽ void *则不同,任何类型的指针都可以直接赋值给它,⽆需进⾏强制类型转换:
void *p1;
int *p2;
p1 = p2;
但这并不意味着, void *也可以⽆需强制类型转换地赋给其它类型的指针。因为“空类型”可
以包容“有类型”,⽽“有类型”则不能包容“空类型”。⽐如,我们可以说“男⼈和⼥⼈都是⼈”,
但不能说“⼈是男⼈”或者“⼈是⼥⼈”。下⾯的语句编译出错:
void *p1;
int *p2;
p2 = p1;
提⽰“'=' : cannot convert from 'void *' to 'int *'”。
void 修饰函数返回值和参数
【规则 1-33】如果函数没有返回值,那么应声明为 void 类型
在 C 语⾔中,凡不加返回值类型限定的函数,就会被编译器作为返回整型值处理。但
是许多程序员却误以为其为 void 类型。例如:
add ( int a, int b )
{
return a + b;
}
int main(int argc, char* argv[]) //甚⾄很多⼈以为 main 函数⽆返回值
//或是为 void 型的
{
printf ( "2 + 3 = %d", add ( 2, 3) );
}
程序运⾏的结果为输出: 2 + 3 = 5
这说明不加返回值说明的函数的确为 int 函数。
因此,为了避免混乱,我们在编写 C 程序时,对于任何函数都必须⼀个不漏地指定其
类型。如果函数没有返回值,⼀定要声明为 void 类型。这既是程序良好可读性的需要,也
是编程规范性的要求。另外,加上 void 类型声明后,也可以发挥代码的“⾃注释”作⽤。所
谓的代码的“⾃注释”即代码能⾃⼰注释⾃⼰。
谓的代码的“⾃注释”即代码能⾃⼰注释⾃⼰。
【规则 1-34】如果函数⽆参数,那么应声明其参数为 void
在 C++语⾔中声明⼀个这样的函数:
int function(void)
{
return 1;
}
则进⾏下⾯的调⽤是不合法的: function(2);
因为在 C++中,函数参数为 void 的意思是这个函数不接受任何参数。
但是在 Turbo C 2.0 中编译:
#include "stdio.h"
fun()
{
return 1;
}
main()
{
printf("%d",fun(2));
getchar();
更多免费资源:www.fishc
}
编译正确且输出 1,这说明,在 C 语⾔中,可以给⽆参数的函数传送任意类型的参数,
但是在 C++编译器中编译同样的代码则会出错。在 C++中,不能向⽆参数的函数传送任何
参数,出错提⽰“'fun' : function does not take 1 parameters”。
所以,⽆论在 C 还是 C++中,若函数不接受任何参数,⼀定要指明参数为 void
void 指针
【规则 1-35】千万⼩⼼⼜⼩⼼使⽤ void 指针类型。
按照 ANSI(American National Standards Institute)标准,不能对 void 指针进⾏算法操作,
即下列操作都是不合法的:
void * pvoid;
pvoid++; //ANSI:错误
pvoid += 1; //ANSI:错误
ANSI 标准之所以这样认定,是因为它坚持:进⾏算法操作的指针必须是确定知道其指
向数据类型⼤⼩的。也就是说必须知道内存⽬的地址的确切值。
例如:
int *pint;
pint++; //ANSI:正确
但是⼤名⿍⿍的 GNU(GNU's Not Unix 的递归缩写)则不这么认定,它指定 void *的算法
操作与 char *⼀致。因此下列语句在 GNU 编译器中皆正确:
pvoid++; //GNU:正确
pvoid += 1; //GNU:正确
在实际的程序设计中,为符合 ANSI 标准,并提⾼程序的可移植性,我们可以这样编写
实现同样功能的代码:
void * pvoid;
(char *)pvoid++; //ANSI:正确; GNU:正确
(char *)pvoid += 1; //ANSI:错误; GNU:正确
GNU 和 ANSI 还有⼀些区别,总体⽽⾔, GNU 较 ANSI 更“开放”,提供了对更多语法
的⽀持。但是我们在真实设计时,还是应该尽可能地符合 ANSI 标准。
【规则 1-36】如果函数的参数可以是任意类型指针,那么应声明其参数为 void *。
典型的如内存操作函数 memcpy 和 memset 的函数原型分别为:
void * memcpy(void *dest, const void *src, size_t len);
void * memset ( void * buffer, int c, size_t num );
这样,任何类型的指针都可以传⼊ memcpy 和 memset 中,这也真实地体现了内存操作
函数的意义, 因为它操作的对象仅仅是⼀⽚内存, ⽽不论这⽚内存是什么类型。如果 memcpy
和 memset 的参数类型不是 void *,⽽是 char *,那才叫真的奇怪了!这样的 memcpy 和 memset 明显不是⼀个“纯粹的,脱离低级趣味的”函数!

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。