C---数据类型

1 数据类型的意义
① inta = 5; // 申请空间并初始化
一个变量必然包含以下概念(变量的四要素): 名字(变量名) ; 值(变量的内容) ; 类型(※);地址(变量在内存中所处的位置)
②同一块内存的不同视角
void main( ) 
{
float f = 34.5f; //对于一块内存,按浮点型初始化
int* ip= (int*)(&f);
printf("thefloat : %f\n", f); //以浮点视角看
printf("theint: %d\n", *ip); //以整型视角看
}
运行结果:  the float: 34.500000   
                      the int: 1107951616 
③定义了数据占用的内存空间大小;
   定义了数据的取值范围;
   定义了数据在内存中的存储格式;
   决定了数据的运算规则;
   为编译器提供了检查依据。
④数据类型起作用的时机数据类型起作用的时机在编译时。等到运行时则所有的事情都以确定下来了。
编译完成的结果——机器码,仅仅是CPU运行的指令集,此时不再作任何判断,就是执行而已。
——————编译器需要知道某个特定值是属于哪种数据类型的,以便正确解释数据。
⑤多字节的数据在内存中如何存放
intb = 0x12345678 ;、
高地址  12  |  34  |  56  |  78   低地址
高地址  78  |  56  |  34  |  12   低地址
数据对齐的端模式(Endian)与处理器有关,分为两种:
小端对齐,将低位存放在低地址。如Intel 80X86系列。 小端对齐:高地址  12  |  34  |  56  |  78   低地址
大端对齐,将高位存放在低地址。如PowerPC处理器。大端对齐:高地址  12  |  34  |  56  |  78   低地址
⑥直接使用ALT + 6 观察内存。inti = 0x12345678;


2 结构体类型
①常识:32位的CPU因为字长是32位的,所以读内存数据时,一次会读取4字节的内容,
且读取的4个字节数据的首地址是被4整除的(0、4、8、c)!即一次读取
0,1, 2,3这样的连续的地址,而2,3,4,5这样的地址只能读取两次!
  struct A    {char c1;      int a;          float f;       char c2;    }       sizeof(struct A) 是16         
  struct B    {char c1; char c2;      int a;         float f;       }       sizeof(struct B) 是12
② 为了加快CPU的存取速度,C编译器在处理数据时,把结构体变量中的成员的
摆放按照某个对齐原则规划,这就叫边界对齐。
sizeof(struct A) = 16;就是因为这个原因。是编译器为了使数据对齐而在结构中加上了一些空位造成的。
边界对齐的细节和编译器实现相关,一般满足三个准则:
~结构体变量的首地址能够被其最宽基本类型成员大小与4的较小者所整除;
~结构体每个成员相对于结构体首地址的偏移量(offset)都是该成员大小与对齐基数中的较小者的整数倍,
如有需要编译器会在成员之间加上填充字节;(默认对齐基数是8);
~结构体的总大小为结构体最宽基本类型成员大小与对齐基数中的较小者的整数倍,
如有需要编译器会在最末一个成员之后加上填充字节。
③“对齐”的规则补充
由于结构体的成员可以是复合类型,比如是另外一个结构体A
A.在寻找最宽基本类型成员时,应当包括复合类型成员A的子成员,而不是把复合成员A看成是一个整体。
B.但在确定复合类型成员A的偏移位置时则是将复合类型作为整体看待。
[偏移量(offset)都是该复合类型成员A的最大子成员大小与对齐基数中的较小者的整数倍]


3 指针类型
int a = 0;        //申请空间并初始化
int *p = &a;   //基本类型所衍生出来的
其他修饰变量的关键字:volatile    const    extern    register    static
①volatile  
重要性:  (假定x为全局变量)int x = 0,val1,val2; val1 = x; …/*一些不使用x的代码*/ val2 = x;
编译器可能将x优化存到寄存器当中。而x是易变的变量,在两次访问中可能x的值变化了,
则访问x应该使用内存中的“原版”
volatile int x;//对该变量不进行寄存器优化
②const 
可以保护被修饰的东西,防止意外的修改,增强程序的健壮性。
int * const p = &i; 常指针,指针永远指向同一个内存地址
const int * p =&i;   指向常量的指针,不能通过指针p来改变变量    
③register 
register inti = 10;
寄存器变量--可以被存储在cpu寄存器中,这仅仅是个请求,未必成功
可以使用register声明的类型是有限的,例如,处理器可能没有足够大的寄存器来容纳double类型。
寄存器数量有限,寄存器不够时候变量申请放到寄存器中也未必成功
④static 
修饰变量—该变量变成静态变量 static int i;
如果是静态局部变量,影响变量的生存期(和普通局部变量比较起来更“长命”),
作用域不变,仍然由函数块域限制(即“{}”限制)。
如果是全局静态变量,生存期不变(和全局变量比较起来一样“长命”),
但将变量访问本地化(作用域在本.C文件)。
修饰函数 static void fun(){} 将函数的调用本地化,只可以由本.C中的其他函数调用。
⑤extern 
修饰变量  extern int i;变量声明,不是定义,随后可能要使用该变量,无论该变量在其他.C中实现(定义),
还是在本.C中实现(定义)都可以继续访问变量
修饰函数  extern void fun();要引用某函数的声明,不是实现(定义)。引用后可以调用该函数,
无论该函数在其他.C中实现(定义),还是在本.C中实现
这两个结论的前提是变量定义时或者函数实现时没有static修饰!也就是说static比extern强硬!




评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值