优秀的编程知识分享平台

网站首页 > 技术文章 正文

C语言变量本质(c语言中变量的本质)

nanyue 2024-08-25 10:36:48 技术文章 6 ℃

变量的本质是什么?是一段内存空间,它是程序一定时间内,运行过程中,对其进行读写的地方。

变量的名称代表的是内存空间地址,除去变量迷人的外表:整型,字符型,长整型,指针类型,数组 剩下的就是内存空间。说到空间,就要注意无非大小,方圆几里?起于何处,止于何方。

那些定义变量的时候叫整型的,或是字符型的是告诉我们世界这么大,然而变量的心就这么大,只能容下这么点心事,多的承受不起。不要超过我的空间大小,我地界之外都是法外之地,到那里苦海无边,回头是岸,家门之内保你无灾无妄,是你的心安之处。

现在你明白了所谓变量,加上那些花花绿绿的类型都是都是骗人的,他就是一块内存里的给那个变量名为xxx的自留地,变量名称就是让你知道他的地址在哪,你需要他指引你到达你想要到达内存空间。

分配给你的自留地是个不毛之地,你要用之前你得清理,初始化它,让他干干净净的,要不然他就不是你认为的样子。记住没有初始化变量就使用这是个祸害,千刀万剐的行为,等到有问题的时候就是程序不死,你不能死,他死你更不能死。这是先辈们死在沙滩上血泪教训,不是危言耸听,昨天我写的C语言翻车现场去看看就知道了。

好了言归正传,如果你的自留地够大,你除了种花,种草甚至种树都可以。了解变量空间的本质,你就发现原来C语言世界这么大,有这么多神来之笔。

请看下图演示代码

1 #include <stdio.h>

2 int main(int argc,char *argv[])

3 {

4 int i = 0;

5 char c = 1;

6 int j = 4417;

7

8 i = c;

9 c = j;

10

11 printf("sizeof(i)=%ld,i=%d,sizeof(c)=%ld,c=%d,c=%c\n",sizeof(i),i,sizeof(c),c,c);

12 printf("Hex (65)=%0x, Dec (0x1141)=%d\n",65,0x1141);

13 return 0 ;

14 }

程序会输出什么呢?说说你的答案?编译不通过,报类型错误?很遗憾没有!内存溢出报segment fault! 这个也没有!!!

使用如下的编译命令,一点错误也没有

gcc -Wall -o test test.c

./test

结果输出如下

这回明白了吗,C语言才不关心你的变量叫什么,你是什么类型,他只认那个叫XXX变量的内存自留地,这地有多大。所以 i = c; 没有任何问题 ,i,c 的空间大小分别为sizeof(i)=4,而sizeof(c)=1 i 容下 c 一点压力都没有,但c = j; 呢为什么没有内存溢出呢?答案是编译器帮你自动转换了,j的十六进制值是0X1141,被截断了j的高位字节,只取了第一个字节41所以变成c的数值是65,ASCII码对应的字符是A。对于C语言来说c这个变量只有种一盘花的空间,是种不下j这个大树的,结果只能砍掉这棵树一部分再分给c变量。

从上面可以看到C语言给了开发人员很大的自由,这种自由更接近计算机底层本质上处理过程,因为对于计算机来说这个是个空间,只是你要读写多少的数据问题。只要这个空间是你的进程可访问的地址那么是不受限制的,你需要自己维护这个空间里数据的完整、一致性、干净,给自己留一片净土。所以不要执迷于变量的类型,受困于这个类型到底能不能赋值,能不能这样。自留地是你的,你想种什么花,什么草,什么树那是你的自由。

明白这个你就知道了你定义了一个缓冲char array[1024](什么缓冲?没错这叫缓冲 ,教材叫字符数组,到你那就成了字符串)这个缓冲能放结构类型,能放长整型,能放字符型,浮点型等等。假如有这个一个需求你需要跟银行进行代收业务交易。你交易的协议约定如下

首1,2字节是包长度 数值, 第3,4,5节是版本号 字符, 第6,7,8,9,10,11字节是本次会话ID 字符往下是包体,包体内容有字符又有数值,但是又如何写入数据呢,记住变量本质是空间,这个空间是可放不同类型(切确说是不同大小长度)内容的空间

请看下面完整的演示代码,就明白如何写入不同的类型了

1 #include <stdio.h>

2 #include <string.h>

3 int main(int argc,char *argv[])

4 {

5 short pkglen=512 ; /* 包长 */

6 char version[4]={"1.0"}; /* 版本 */

7 char sessionid[6]={"123456"}; /* 会话ID */

8 char buf[1024];

9 char *pBuf = buf;

10

11 /* 封装数据包 */

12 *((short *)pBuf) = pkglen;

13 pBuf = pBuf +2;

14 sprintf(pBuf,version);

15 pBuf = pBuf + strlen(version);

16 sprintf(pBuf,sessionid);

17 pBuf = pBuf +strlen(pBuf);

18

19 /* 解析包 */

20 pBuf = buf;

21 short len = *((short *)pBuf);

22 char v[4];

23 strncpy(v,pBuf + 2,3);

24 v[3]='\0';

25 char s[6];

26 strncpy(s,pBuf + 2 +3,5);

27 s[5]='\0';

28 printf("pkglen=%d,version=%s,sessionid=%s\n",len,v,s);

29 return 0 ;

30 }

结果如下

接着来说说变量的类型,类型切确的说是在C语言中对变量进行操作时每次处理的位宽,例如int 在64位,gcc编译器下属

4字节的长度,对某个变量的读写每次都是相同的位宽,也是指针前进后退的步长。类型的作用就是告诉计算机每次处理的单元大小

看一下如下代码演示

1 #include <stdio.h>

2 #include <string.h>

3 int main(int argc,char *argv[])

4 {

5 char array[11]="";

6 strncpy(array, "1234567890", 10);

7 char *p = array;

8

9 p++;

10 printf("*p = %c, addr = %ld\n",*p, p);

11

12 p = p +3;

13 printf("*p = %c, addr = %ld\n",*p, p);

14

15 int *pi =(int *) array;

16 pi++;

17 printf("*pi = %c, addr = %ld\n",*pi,pi);

18 }

输出:

第一次 p++; 运行后p现在的位置是相对于array 地址的下一个字节处,也就是p前进的位宽是sizeof(char),即array[1]的地址,所以打印出来的结果是2

而pi++;pi 类型的位宽是4个字节,那么执行pi++后相当于往后走了四步sizeof(char)的大小,但只走了一步sizeof(int),可以看到程序的输出结果最后p和pi的地址是

相等的,也就是说他们现在都是同一个地方

这就是类型的本质,它限定了每次读写的位宽,是按固定位宽单元去访问。如同之前的12 *((short *)pBuf) = pkglen;

pBuf本来是char在转换成short后写入pkglen,直接往长度为4的内存里写了512,读者想想如果是一个结构的类型呢?

总之要记住变量的本质是一段内存空间,它的名称代表内存空间的位置,而它的类型是读写的位宽。

Tags:

最近发表
标签列表