cpu的位数代表着cpu一次性能够处理的数据的位数,而CPU是通过地址总线、数据总线、控制总线三条线与内存进行数据传输与操作。我们要明白,指针就是地址,地址就是指针。 而地址是内存单元的编号。所以,一个指针占几个字节,等于是一个地址的内存单元编号有多长,就是地址总线的宽度。
int的长度,是由硬件和系统共同决定的。
当年的dos是运行在16位CPU下的,他的int是两个字节,
win95是运行在32位CPU下的,但是win95还是16位的系统设计,所以他的int是2个字节,
到2000,NT,XP,cpu是32位的,windows也支持32位,所以他的int是4字节
语言并没有规定类型的长度,但是有一些规则,比如:char不论在什么时候都是一个字节(即8个bit),int永远比char长,长整型至少和整型一样长,整型至少和短整型一样长(short<=int<=long)。
| 数据类型 | 16bit编译器(字节) | 32bit编译器(字节) | 64bit编译器(字节) |
| char | 1 | 1 | 1 |
| short int | 2 | 2 | 2 |
| int/unsigned int,依赖于编译器 | 2 | 4 | 4 |
| long/unsigned long,依赖于编译器 | 4 | 4 | 8 |
| Char *(指针类型),依赖于编译器 | 2 | 4 | 8 |
| float | 4 | 4 | 4 |
| double | 8 | 8 | 8 |
综上:
从16bit升级至32bit时,int所占的字节数将发生变化。
从32bit升级至64bit时,long所占的字节数将发生变化。
指针占的位数=地址总线的宽度,
数据总线的宽度=字长=cpu的位数=cpu一次性能够处理的数据的位数
最后提一下取值范围
| 数据类型 | 取值范围 |
|---|---|
| signed char = char | -128 ~ +127 (1 Byte) |
| signed short = short | -32767 ~ + 32768 (2 Bytes) |
| unsigned short | 0 ~ 65536 (2 Bytes) |
| signed int = int | -2147483648 ~ +2147483647 (4 Bytes) |
| unsigned int | 0 ~ 4294967295 (4 Bytes) |
大部分体系结构上, char默认是带符号的,它可以自-128到127之间取值。也有一些例外,比如ARM体系结构上,char 就是不带符号的,它的取值范围是0~ 255。
根据国际标准IEEE(电气和电子工程协会) 754,任意一个二进制浮点数V可以表示成下面的形式:
(-1)^S * M * 2^E
(-1)^s表示符号位,当s=0,V为正数;当s=1,V为负数。
M表示有效数字,大于等于1,小于2。
2^E表示指数位。
举例来说: 十进制的5.0,写成二进制是 101.0 ,相当于 1.01×2^2 。 那么,按照上面V的格式,可以得出s=0,M=1.01,E=2。
十进制的-5.0,写成二进制是 -101.0 ,相当于 -1.01×2^2 。那么,s=1,M=1.01,E=2。
IEEE 754规定: 对于32位的浮点数,最高的1位是符号位s,接着的8位是指数E,剩下的23位为有效数字M。

对于64位的浮点数,最高的1位是符号位S,接着的11位是指数E,剩下的52位为有效数字M。

IEEE 754对有效数字M和指数E,还有一些特别规定。 前面说过, 1≤M<2 ,也就是说,M可以写成 1.xxxxxx 的形式,其中xxxxxx表示小数部分。
IEEE 754规定,在计算机内部保存M时,默认这个数的第一位总是1,因此可以被舍去,只保存后面的xxxxxx部分。
比如保存1.01的时候,只保存01,等到读取的时候,再把第一位的1加上去。这样做的目的,是节省1位有效数字。
以32位浮点数为例,留给M只有23位,将第一位的1舍去以后,等于可以保存24位有效数字。至于指数E,情况就比较复杂。
首先,E为一个无符号整数(unsigned int) 这意味着,如果E为8位,它的取值范围为0255;如果E为11位,它的取值范围为02047。但是,我们知道,科学计数法中的E是可以出现负数的,所以IEEE 754规定,存入内存时E的真实值必须再加上一个中间数,对于8位的E,这个中间数是127;对于11位的E,这个中间数是1023。比如,2^10的E 是10,所以保存成32位浮点数时,必须保存成10+127=137,即10001001。
然后,指数E从内存中取出还可以再分成三种情况:
a)E不全为0或不全为1
这时,浮点数就采用下面的规则表示,即指数E的计算值减去127(或1023),得到真实值,再将有效数字M前加上第一位的1。 比如: 0.5(1/2)的二进制形式为0.1,由于规定正数部分必须为1,即将小数点右移1位,则为1.0*2^(-1),其阶码为-1+127=126,表示为01111110,而尾数1.0去掉整数部分为0,补齐0到23位00000000000000000000000,则其二进制表示形式为: 00 01111110 00000000000000000000000
b)E全为
这时,浮点数的指数E等于1-127(或者1-1023)即为真实值, 有效数字M不再加上第一位的1,而是还原为0.xxxxxx的小数。这样做是为了表示±0,以及接近于0的很小的数字。
c)E全为1
这时,如果有效数字M全为0,表示±无穷大(正负取决于符号位s);
好了,关于浮点数的表示规则,就说到这里。
局部变量在函数内定义,全局变量在函数外定义

a)静态局部变量
在介绍静态局部变量之前,我们先了解一个概念:静态,在C语言中我们使用关键字static来表示静态,当我们在定义变量时,一般的说在函数内部定义的变量我们称之为局部变量,在定义时对其前面加上关键字static,则此局部变量就是静态局部变量 ,我们举个简单的例子:
void Func()
{
static int n; //定义一个整形变量的静态局部变量n。
}
按照其字面意思,就是它的作用域只对局部有用,所以一般的说静态局部变量的作用域就是函数内部,只是在某一个块中发挥作用,而静态局部变量的生命周期是:函数进入时创建,程序退出时消亡,这里就涉及到计算机为其分配的内存区域。
当我们创建一个项目时,计算机会将欲分配的内存区域大致分为4个区域:第一个是代码区(段),第二个是全局(静态)变量区,第三个是栈,第四个是堆。而我们所定义的各种变量会按照其属性分别存放在不同的区域。就比如说,静态局部变量会存放在全局(静态)变量区,而普通局部变量会存放在栈内。
b)普通局部变量
对于普通局部变量,就是我们一般的在函数体内或者在主函数main()内部定义的变量,其作用域和静态局部变量是一样的,都只作用于某一个块内,或者说某一个函数体内。它的生命周期是:函数进入时创建,函数退出时消亡,举个简单的例子:
void Func()
{
int n; //定义一个整形变量的普通局部变量n。
}
【注】对于普通局部变量和静态局部变量来说,没有链接属性这个概念,是因为局部变量只是在函数体内作用,并不能将其通过链接扩大其作用域。
总结:对于局部变量,通俗点说就是定义在函数内部的变量,其作用域只是函数内部,退出函数体就失去其作用,若在对其进行调用程序会出错,例如:
int Sumc(int a, int b)
{
int sum; //定义一个整形变量的局部变量sum
sum = a + b; //变量a,b,sum均为局部变量,只在函数Sumc中发挥作用
return sum; //返回两个整数a,b的和
}
int main()
{
int n; //定义一个整形变量的局部变量n,只在主函数main()中发挥作用
}
a)普通全局变量
全局变量,通俗的理解,就是其在全局也即整个文件中发挥作用 ,从其作用域理解,它在定义的时候,就必须定义在函数体外部,或者主函数的外部,对于普通的全局变量,它的生命周期是在程序运行时创建,在程序退出时消亡。
【注】对于全局变量,不论是普通全局变量,还是静态全局变量,其内存区域均在全局(静态)变量区。
b)静态全局变量
类似于静态局部变量的定义,在定义全局变量的时候在其前面加上关键字static,即为静态全局变量。对于静态全局变量,它的作用域是整个文件,生命周期是程序运行时创建,程序退出时消亡,它存储在全局(静态)变量区,举个简单的例子:
static int n = 0; //定义一个静态全局变量n,并且初始化为0,其作用域是整个文件,也就是对函数Func和main均可用
int m = 0; //定义一个普通全局变量m,并且初始化为0,其作用域是整个文件
void Func()
{
int n; //定义一个整形变量的普通局部变量n,其作用域是函数Func()内部
}
int main()
{
char str; //定义一个char类型的普通局部变量str,其作用域是主函数main()内部
}
如下代码,我们在函数体外定义一个全局变量sum,此时,可以在函数Func中使用,也可以在主函数main中使用。
c)全局变量和局部变量的比较
1.比较
| 生命周期 | 作用域 | 默认值 | 内存区域 | 链接属性 |
|---|---|---|---|---|
| 普通局部变量 | 函数进入时创建,函数退出时消亡 | 函数内 | 随机值 | 栈 |
| 静态局部变量 | 函数进入时创建,程序退出时消亡 | 函数内 | 0 | 全局(静态)变量区 |
| 普通全局变量 | 程序运行时创建,程序退出时消亡 | 整个文件内 | 0 | 全局(静态)变量区 |
| 静态全局变量 | 程序运行时创建,程序退出时消亡 | 整个文件内 | 0 | 全局(静态)变量区 |
2.静态关键字:static
static 是 C/C++ 中很常用的修饰符,它被用来控制变量的存储方式和可见性。在C语言中,关键字static主要定义全局静态变量、定义局部静态变量、定义静态函数。
static可以修改变量或者函数的声明周期,默认值,内存区域,链接属性。
举个简单的例子:
int a; //普通全局变量 程序创建时生成,程序退出时消亡 全局(静态)变量区 整个文件内 外部 默认值:0
static int b; //静态全局变量 程序创建时生成,程序退出时消亡 全局(静态)变量区 整个文件内 内部(加extern变为外部) 默认值:0
const int c = 10; //全局变量(默认为静态) 内部 程序创建时生成,程序退出时消亡
int main()
{
int d; //普通局部变量 函数(代码块)创建时生成,函数退出时消亡 函数内 栈内 默认值:随机值
static int e; //静态局部变量 函数创建时生成,程序退出时消亡 函数内 全局(静态)变量区
const int f = 20; //局部变量 函数创建时生成,函数退出时消亡 函数内
for (int i = 0; i < 10; i++) //i是局部变量 块创建时生成,块结束时消亡 块内可见
{
printf("%d\n", i);
}
return 0;
}
extern:声明外部全局变量,注意:extern只能用于声明,不能用于定义。(个人理解:声明可以多次,定义只能一次。毕竟全局范围是所有文件,影刺所有文件中只能有一次定义)
extern工作原理:先会去当前文件下查找有没有对应全局变量,如果没有,才回去其他文件查找
extern的原理很简单,就是告诉编译器:“你现在编译的文件中,有一个标识符虽然没有在本文件中定义,但是它是在别的文件中定义的全局变量,编译器你要放行!”
前面的全局变量,全局即整个文件。
有了extern,就可以声明以所有文件为全局范围的全局变量变量。