网站建设与管理 答案,浙江电商网络推广,哪个网站可以做体育主播,织梦如何做视频网站之前的两篇文章
嵌入式Linux#xff1a;c语言深度解剖#xff08;数据类型关键字#xff09;zhuanlan.zhihu.com
嵌入式Linux#xff1a;c语言深度解剖#xff08;入门篇#xff09;zhuanlan.zhihu.com
这篇文件继续讲解C语言关键字
想问大家一个问题#xff0c…之前的两篇文章
嵌入式Linuxc语言深度解剖数据类型关键字zhuanlan.zhihu.com
嵌入式Linuxc语言深度解剖入门篇zhuanlan.zhihu.com
这篇文件继续讲解C语言关键字
想问大家一个问题什么是声明什么是定义
举个例子
A)int i
B)extern int i(关于 extern后面解释)
哪个是定义哪个是声明或者都是定义或者都是声明
什么是定义所谓的定义就是(编译器)创建一个对象为这个对象分配一块内存并给它取上一个名字这个名字就是我们经常所说的变量名或对象名。但注意这个名字一旦和这块内存匹配起来它们就同生共死终生不离不弃。并且这块内存的位置也不能被改变。一个变量或对象在一定的区域内比如函数内全局等只能被定义一次如果定义多次编译器会提示你重复定义同一个变量或对象。
什么是声明有两重含义如下
第一重含义告诉编译器这个名字已经匹配到一块内存上了就比如你拿出结婚证告诉别人我已经和别的内存块结婚了请不要再勾搭我了。
第二重含义告诉编译器我这个名字我先预定了别的地方再也不能用它来作为变量名或对象名。这个就有点耍赖你拿着一个假的结婚证告诉别人我已经结婚了但是实际上你还没有妹子还没有分配内存空间。
好这样一解释我们可以很清楚的判断:A)是定义B)是声明。
那他们的区别也很清晰了。记住定义声明最重要的区别定义创建了对象并为这个对象一块内存而声明的时候是没有分配内存空间的。 1不需要记住的关键字----auto auto他太普通了你就当它不存在吧。编译器在默认的缺省情况下所有变量 都是 auto 的。2最快的关键字---- register register这个关键字请求编译器尽可能的将变量存在 CPU 内部寄存器中而不是通过内 存寻址访问以提高效率。注意是尽可能不是绝对。你想想一个 CPU 的寄存器也就那么 几个或几十个你要是定义了很多很多 register 变量它累死也可能不能全部把这些变量放 入寄存器吧轮也可能轮不到你。2.1皇帝CPU身边的小太监----寄存器
把cpu类比成为一个皇帝那register就是皇帝身边的小太监了不知道大家见过太监没有我们看各种宫斗剧的时候太监是唯命是从只要皇帝叫做什么太监马上就去做速度之快令人瞠目结舌也就是因为速度快所以皇帝才配有太监而且不止有一个太监太监就像一个文件中转站把下面人的折子拿给皇帝批阅。
所以太监的特点是
1、响应速度快
2、数量少只给皇帝工作
3、价格贵
2.2使用 register 修饰符的注意点 虽然寄存器的速度非常快但是使用 register 修饰符也有些限制的register 变量必须是能被 CPU 寄存器所接受的类型。意味着 register 变量必须是一个单个的值并且其长度应小于或等于整型的长度。 而且 register 变量可能不存放在内存中所以不能用取址运算符“”来获取 register 变量的地址。
3、确定位置的关键字----static
3.1、static 修饰变量
修饰静态全局变量作用域仅限制于被定义的文件中其他文件即使用extern声明也没有办法使用作用域从定义之处开始到文件结尾处在定义之前的代码不能使用。本文件可以在之前加extern 不过这样还不如直接在顶端定义。 静态全局变量在函数体里面定义的就只能在函数里面使用了由于static定义的变量存在静态区改函数执行结束变量的值还是存在不会销毁下次该函数调用时static定义的变量值是上一次调用时候的值。
3.2、static修饰函数
在函数前面加static表示函数成为静态函数表示该函数的作用域仅限于定义处到文件结尾。如果全局函数有一个函数名字和静态函数一样的名字编译器不会报错使用本文件的静态函数运行。
#include stdio.hstatic int j;void func1(void)
{static int i 0;i;printf(i %d\n, i);
}void func2(void)
{j 0;j;printf(j %d\n, j);
}int main(int argc, char *argv[])
{int k 0;for(k 0; k10; k){func1();func2();printf(\n);}return 0;
}大家运行上面代码加深下对static的理解 4、大喇叭关键字----extern
上面有一个例子已经说到了extern,extern就像一个大喇叭一样他不分配内存就是不讨老婆但是总是跟别人说谁谁娶媳妇了这个标识符就定义了这个函数被定义了如此如此不过这个大喇叭非常有用比如他可以跟编译器说这个家伙已经讨老婆了你可以用他生孩子了就不要再让他二婚了。
既然extern不能给别人发结婚证那么下面这个
extern int i 10;
是否有问题
不能发结婚证就是不能分配内储存没有内存怎么把10存下来所以肯定是错的。 5、让cpu最累的关键字----volitile
volitile这个关键字让cpu非常累每次运行到他的位置都要去内存重新确定他的值在中断的使用的变量最好用这个关键字修饰因为中断的变量你不知道什么时候会被改变volatile的变量是说这变量可能会被意想不到地改变这样编译器就不会去假设这个变量的值了。说白了就是不能让cpu偷懒所以说是类似老大CPU了。 6、只能读的关键字----const
const可以理解为别人只能来读我的值不能改变我有的人写代码加上这个就是担心自己的值被改变比如const int i 5;下一次i 6;这就是有问题的i 的值已经确定了就像define一样不过define不是关键字。
/************************************************************************* File Name: const.c Author: Mail: Created Time: Mon 29 Oct 2018 02:33:19 PM CST************************************************************************/#includestdio.h
#define M 3
const int N 5; void main(void)
{ printf(%p\n,N);int i M; int j N; printf(%p\n,N); int x M; int y N; printf(%p %p %p %p\n,i,j,x,y);printf(%d %d %d %d\n,i,j,x,y);
} 7、不色不空的关键字----void
大家可以看看void 和void* 谁是色谁是空呢void 表示这个是空的什么都没有比如void i; 我们定义一个空的i这就有问题了这个i编译器到底要不要给他分配空间呢就是这样的情况编译器报错了你搞什么飞机给我一个空的东西还想让我给你讨老婆。
但是void 不一样void *表示所有类型的指针这就是色啊女人都想入非非。
说明既然提供了void的这两种用法就去运用。即函数没返回值就将其返回值类型写为void函数没有形参就将其形参写为void。不了解编译器默认操作时不要依赖。即使了解其默认操作也别依赖因为肯定有人不了解的这样别人就看不懂你的代码了。
大家看看这个是否正确
add(int a,int b)
{return (ab);
}下面两个函数就是用void*作为返回值
memcpy
原型extern void *memcpy(void *dest, void *src, unsigned int count);
用法#include
功能由src所指内存区域复制count个字节到dest所指内存区域。
说明src和dest所指内存区域不能重叠函数返回指向dest的指针。
注意与strcpy相比memcpy并不是遇到\0就结束而是一定会拷贝完n个字节。 memset
原型extern void *memset(void *buffer, int c, int count);
用法#include
功能把buffer所指内存区域的前count个字节设置成字符c。
说明返回指向buffer的指针。
8、return 关键字
return 关键字终止一个函数并返回一个值。
#include stdio.hadd(int a,int b)
{return (ab);
}char * str(void)
{char *strc This is c\n;return strc;
}main(void)
{printf(%d\n,add(1,4));printf(%s\n,str);return ;
}看看上面这个函数的输出会有陷阱的
9、柔性数组
讲了很多关键字现在讨论一个酷的东西以后也会经常用到柔性数组是可以自由变化长度的数组对开发上来说是非常有用的。
C99中结构体的最后一个元素允许是未知大小的数组这就叫做柔性数组成员但结构体的柔性数组成员前面必须至少一个其他成员。
#includestdio.h
typedef struct _SoftArray{int len;int array[];
}SoftArray;int main()
{int len 10;printf(The structs size is %d\n,sizeof(SoftArray));
}我们可以看出_SoftArray结构体的大小是4显然在32位操作系统下一个int型变量大小刚好为4也就说结构体中的数组没有占用内存。为什么会没有占用内存我们平时用数组时不时都要明确指明数组大小的吗但这里却可以编译通过呢这就是我们常说的动态数组也就是柔性数组。
#includestdio.h
#includemalloc.h
typedef struct _SoftArray{
int len;
int array[];
}SoftArray;
int main()
{int len10,i0;SoftArray *p(SoftArray*)malloc(sizeof(SoftArray)sizeof(int)*len);p-lenlen;for(i0;ip-len;i){p-array[i]i1;}for(i0;ip-len;i){ printf(%d\n,p-array[i]);}free(p);return 0;
}这代码的作用是用柔性数组动态创建数组并输出数组内容这里我就直接解释解释这两句代码 SoftArray* p (SoftArray*)malloc(sizeof(SoftArray) sizeof(int) *10);p-len 10;第一句主要是根据你要定义的数组长度和数据类型以及柔性数组本身的大小来开辟一块内存空间给柔性数组第二个是定义len的长度便于确定循环打印输出
觉得对你有用请关注微信公众号【嵌入式Linux】