😁博客主页😁:🚀https://blog.csdn.net/wkd_007🚀
🤑博客内容🤑:🍭嵌入式开发、Linux、C语言、C++、数据结构、音视频🍭
🤣本文内容🤣:🍭介绍标准C语言的32个关键字🍭
😎金句分享😎:🍭有机会一定要试试,其实试错的成本并不高,而错过的成本很高🍭
C语言32个关键字详解(1):数据类型部分(char、short、int、long、float、double、struct、union、enum、void)
C语言32个关键字详解(2):修饰类型部分(auto、signed、unsigned、static、extern、const、register、volatile)
C语言32个关键字详解(3):结构语句部分(if、else、switch、case、default、do、while、for、break、continue、return、goto)
C语言32个关键字详解(4):其他(typedef、sizeof)
目录
C语言的关键字有32个,我将它主要分成下面四个方面来介绍。
功能 | 关键字 |
---|---|
类型(10个) | char、short、int、long、float、double、struct、union、enum、void |
修饰类型(8个) | auto、signed、unsigned、static、extern、const、register、volatile |
结构语句(12个) | if、else、switch、case、default、do、while、for、break、continue、return、goto |
其他(2个) | typedef、sizeof |
前面介绍了char、short、int、long、float、double、struct、union、enum、void
;
这篇文章主要介绍auto、signed、unsigned、static、extern、const、register、volatile
这几个与与类型相关的。
一、auto、signed、unsigned
1.1 auto 关键字
写了这么久C语言,你应该很少,甚至没使用过 auto
关键字吧。因为C语言在缺省状态下,编译器默认所有变量都是auto
的,所以加不加auto
都一样。
所以,auto
关键字可以当它不存在!!!不用管它。
1.2 signed 关键字
signed
关键字和auto
一样,也很少用,C语言在缺省状态下,编译器默认数据都是signed
类型的。
所以,signed
关键字可以当它不存在!!!不用管它。
signed
表示有符号的,也就是说,这个变量可以是正数,也可以是负数;
计算机只认识0和1,负数的-
号是无法存入内存的,约定了基本类型最高位为1来表示负数;
数值在计算机系统中一律用补码来存储的:
正数的补码与其原码一致;
负数的补码:为该数绝对值的原码按位取反再加1,最后把最高位写1。
例如:char 型的-5,其补码为:-5的绝对值5(二进制0000 0101
)按位取反得到1111 1010
,再加1等于1111 1011
,再把最高位写1,仍然是1111 1011
(十六进制0xFA
)。所以-5的补码是0xFA
。
1.3 unsigned 关键字
1、char
和 unsigned char
:一般情况下,单纯的char
类型应该只用于字符值的存储和使用;unsigned char
型变量只能用于数值的存储和使用。
2、所有的无符号常量都应该带U后缀:unsigned u_ch= 100U;
3、signed
类型变量和unsigned
类型变量运算的结果是unsigned
类型;
4、unsigned
类型永远大于0,条件判断时千万别写出下面错误
代码:
// `错误`代码演示:
// https://blog.csdn.net/wkd_007/article/details/133932760
unsigned int i = 100;
while(i>=0)// i是unsigned的,所以条件永远满足
{
i--;
printf("i=%u\n",i);
}
5、unsigned
类型使用printf打印时,使用%u
;unsigned long
使用%lu
。
转载请注明:https://blog.csdn.net/wkd_007/article/details/133932760
二、static 关键字
static
关键字可以限定函数或变量的作用域;也可以指明变量存储在内存的哪个区域;
2.1 static 修饰的变量
1、static
修饰的全局变量(静态全局变量):存在内存的静态区
,作用域仅限于变量被定义的文件中,其他文件即使用extern声明也没法使用它。准确的说,作用域是从定义之处开始,到文件结尾处结束,在定义之处前面的那些代码行也不能使用它,想要使用就得在前面再声明它。所以,一般直接在文件顶端定义。
2、static
修饰的局部变量(静态局部变量):在函数体里面定义的,就只能在这个函数里用了,同一个文档中的其他函数也用不了。由于被static修饰的变量总是存在内存的静态区
,所以即使这个函数运行结束,这个静态变量的值也不会被销毁,函数下次使用时仍然能用到这个值。
参考下面代码加深理解:
//static.c
//https://blog.csdn.net/wkd_007
#include <stdio.h>
static int gs_i;
void fun(void)
{
static int s_i = 0;
int i = 0;
printf("gs_i=%d s_i=%d i=%d\n",gs_i++, s_i++, i++);
}
int main()
{
int i=0;
for(i=0; i<10; i++)
{
fun();
}
return 0;
}
2.2 static 修饰的函数
static 修饰的函数是限定其作用域仅在本文件。实际开发中,如果该函数仅在本文件使用,最后加上static
,这样就不怕与其他文件的函数重名。
三、extern 关键字
extern 关键字一般用于声明全局变量
或函数
,作用是告诉编译器,该全局变量
或函数
是本文件外部定义的。
本文件使用extern
声明的全局变量
或函数
,可以直接在本文件该处声明之后正常使用。
参考下面例子加深理解:全局变量extern_val
、函数get_extern_val
定义在extern.c
,在extern_sample.c
使用的话,需要加extern
声明。
//extern.c
int extern_val;
int get_extern_val()
{
return extern_val;
}
// extern_sample.c
#include <stdio.h>
extern int extern_val; // 声明,变量定义在其他文件(extern.c)
extern int get_extern_val();// 声明,函数定义在其他文件(extern.c)
int main()
{
extern_val = 0;
get_extern_val();
return 0;
}
对定义和声明不清楚的可以参照文章:https://blog.csdn.net/wkd_007/article/details/133622725
四、const 关键字
4.1 const修饰的是 只读变量 而不是 常量
C语言中,const
修饰的是 只读变量 而不是 常量;const
修饰的变量,只是表示了该变量不能直接修改,但可以通过它的地址,间接修改;const
修饰的只读变量不能用于case
关键字后面作为判断条件;
参考代码理解:
#include <stdio.h>
int main()
{
const int ci = 100;
printf("ci=%d\n",ci);
// ci=5;// 报错:error: assignment of read-only variable ‘ci’
int *pCi = &ci;// warning: initialization discards ‘const’ qualifier from pointer target type [enabled by default]
*pCi = 5;// 不报错,并间接修改了ci的值
printf("ci=%d\n",ci);
int i = 0;
switch(i)
{
case 1:
break;
//case ci://报错: case label does not reduce to an integer constant
//break;
default:
break;
}
return 0;
}
4.2 const变量与宏常量的区别
const
定义的只读变量从汇编的角度来看,只是给出了对应的内存地址,而不是像#define
宏定义一样给出的是立即数,所以,const
定义的只读变量在程序运行过程中只有一份备份(因为它是全局的只读变量,存放在静态区),而#define
宏定义的宏常量在内存中有若干个备份。宏常量是在预编译阶段进行替换,而const修饰的只读变量是在编译的时候确定其值。宏常量没有类型,而const修饰的只读变量具有特定的类型。
4.3 const修饰的指针
const
在 *
前面,则指针指向的对象不可被改变;
const
在 *
后面,则指针的值不可被改变;
*
的前后都有const
,则指针的值、指针指向的对象的值都不可被修改;
const int *p; // p 可变, p 指向的对象不可变
int const *p; // p 可变, p 指向的对象不可变
int *const p; // p 不可变, p 指向的对象可变
const int *const p; //指针 p 和 p 指向的对象都不可变
4.4 const修饰函数的参数、返回值
void Fun(const int * p);
上面代码const修饰函数的参数,告诉编译器,*p在函数体中不能改变,从而防止了使用者的一些无意的或错误的修改。实际开发中,如果函数参数存在指针,且不希望指针指向的对象被修改,可以加const修饰。
const修饰符也可以修饰函数的返回值,返回值不可被改变。
五、register 关键字
首先,了解一下数据是怎样被CPU处理的?
数据从内存里拿出来先放到寄存器,然后CPU再从寄存器里读取数据来处理,处理完后同样把数据通过寄存器存放到内存里,CPU不直接和内存打交道。
register
关键字请求编译器尽可能地将变量存在CPU内部寄存器中,而不是通过内存寻址访问以提高效率。
注意是尽可能,不是绝对。因为一个CPU的寄存器数量有限。
注意点:
1、register
变量必须是能被cpu寄存器所接受的类型,也就是一个单个的值,并且其长度应小于或等于整型的长度;
2、register
变量可能不存放在内存中,所以不能用取址运算符&
来获取register
变量的地址。
六、volatile 关键字
volatile
关键字的作用是告诉编译器,该变量随时可能发生改变,每次使用它时都从内存中取值,不要对该变量的代码进行优化。
#include <stdio.h>
int main(void)
{
//volatile int i = 10;
int i = 10;
int j = i; // ①语句
int k = i; // ②语句
printf("i=%d j=%d k=%d\n",i,j,k);
return 0;
}
上面代码,因为①②语句中,i
没有被赋值,这时编译器会认为 i
的值没有改变,在①语句时从内存中取出 i
的值赋给 j
,在②语句是,又继续用这个值给 k
赋值。这样优化可以提升效率。
如果 i
使用 volatile
修饰,那么每次使用到 i
,编译器都会从内存取值,不做优化。在一些比较底层的代码(如Linux驱动代码,Linux内核源码)可能需要用到这个关键字。
一个参数既可以是const还可以是volatile吗?如:
const volatile int i = 10;
可以,例如只读的状态寄存器。它是 volatile 因为它可能被意想不到地改变。它是 const 因为 程序不应该试图去修改它。
转载请注明:https://blog.csdn.net/wkd_007/article/details/133932760
如果文章有帮助的话,点赞👍、收藏⭐,支持一波,谢谢 😁😁😁