一、字节对齐
字节对齐-1变量
字节对齐-2结构体
二、结构体
链表 https://www.cnblogs.com/corvoh/p/5595130.html
负数的原码和反码,补码&数据类型强制转换
负数的源码=首位1+对应正数后七位源码:
比如-128源码=1+000_0000(127源码1000_0000)
原码:
一个正数,按照绝对值大小转换成的二进制数就是正数的原码
一个负数,按照绝对值大小转换成的二进制数,然后最高位补1,就是负数的原码
比如
00000000 00000000 00000000 00000101 是5的原码。
10000000 00000000 00000000 00000101 是-5的原码。
反码:
正数的反码与原码相同
负数的反码为对该数的原码除符号位外各位取反
正数00000000 00000000 00000000 00000101 的反码还是 00000000 00000000 00000000 00000101
负数10000000 00000000 00000000 00000101每一位取反(除符号位),得11111111 11111111 11111111 11111010。
补码
正数的补码与原码相同
负数的补码为对该数的原码除符号位外各位取反,然后在最后一位加1
比如:10000000 00000000 00000000 00000101 的反码是:11111111 11111111 11111111 11111010
byte类型的取值范围:有符号的[-128,127] 无符号的[0,255]
对于有符号的数据类型来说:最高位为符号位 0 为正数,1为负数
例如:
5 表示为 0000 0101
-5表示为( 原码):1000 0101 ===> 反码:1111 1010 ===> 补码:1111 1011
-128 的原码,反码,补码:
-128源码1000 0000(128源码=1000 0000→转换成-128即首位1+后7位000_0000)
故-128 补码1000 0000 (1111 1111(反码) + 1 = 1000 0000,这里实际上真正相加的是1111 1111后面的7位,第1位是符号位始终不会变,所以,当进到第8位的时候,溢出了,会被舍弃)
举例:三码之间转换:
int a = 256 ; //1 0000 0000
byte b = a ; //去高位 得到 0000 0000 byte字节=8位
//b=0
// 当a=255=1111 1111时 对于byte来说是负数这是一个负数的补码 ===>
//补码:1111 1111→→反码:1111 1110→→原码 : 1000 0001 b= -1
数据类型强制转换==换一种方式解读数据(不改变存储的数据)
unsigned int a = (unsigned)-1;
printf("%u\n",a); //输出结果是 4294967295
解释:
-1作为负数在计算机中存的是它的补码,它的原码是 1000 0000 0000 0000 0000 0000 0000 0001
补码 为 1111 1111 1111 1111 1111 1111 1111 1111
-1转换成unsigned无符号 即按照unsigned的方式解读
1111 1111 1111 1111 1111 1111 1111 1111
①按照int方式解读→补码1111 1111 1111 1111 1111 1111 1111 1111→反码→源码→-1
②按照unsigned int方式解读→2^32-1=4294967296-1=4294967295
字节对齐-1变量
32位和64位系统区别及字节对齐https://blog.csdn.net/lz20120808/article/details/49910659
32和64位在数据长度上只有2点差异:
①*pointer(即指针变量,只与地址寻址范围有关): 32位的寻址空间是2^32, 即32个bit→4个字节。同理64位编译器→8字节)
②(unsigned) long: 4个字节(32) or 8字节(64位)
其余的都相同
char :1个字节
short int : 2个字节
int: 4个字节
unsigned int : 4个字节
float: 4个字节
double: 8个字节
long long: 8个字节
字节对齐-2结构体
为内存优化,一般采用字节对齐。
字节对齐就是变量存储的地址是变量的有效字节对齐值的整数倍,即:
address%最终有效字节对齐值 = 0;
变量字节对齐值
变量的自身字节对齐值
简单类型变量
对于char型数据,其自身对齐值为1,对于short型为2,对于int,float,double类型,其自身对齐值为4,单位字节。
结构类型或联合类型:
自身字节对齐值的大小是其成员中最大基本类型要求的有效字节对齐值
编译器要求的字节对齐值:
编译器设置要求的字节对齐值
最终有效的字节对齐值:
在自身字节对齐值和编译器要求的字节对齐值中取较小的。
其实字节对齐的细节和具体编译器实现相关,但一般而言,满足三个准则:
1) 结构体变量的首地址能够被其最宽基本类型成员的大小所整除。
2) 结构体每个成员相对于结构体首地址的偏移量都是成员大小或者成员的子成员大小(只要该成员有子成员,比如说是数组,结构体等)的整数倍,如有需要编译器会在成员之间加上填充字节;
3) 结构体的总大小为结构体最宽基本类型成员大小的整数倍,如有需要编译器会在最末一个成员之后加上填充字节。
typedef struct bb
{
int id; //[0]....[3]
double weight; //[8].....[15] 原则2
float height; //[16]..[19],总长要为8的整数倍,补齐[20]...[23] 原则3
}BB;
typedef struct aa
{
char name[2]; //[0],[1]
int id; //[4]...[7] 原则2
double score; //[8]....[15]
short grade; //[16],[17]
BB b; //[24]......[47] 原则2
}AA;
函数
函数参数传递三种方式(传值方式,地址传递,引用传递)
参数传递两种方式–传值&传址
传值方式:实参不受影响,实参拷贝一份→传参[函数结束后被释放]
传址方式:将实参的地址传递给函数,在函数内对形参进行操作等同于对实参进行相同的操作,实参的内容是对形参进行操作后的结果。
传址又分为:引用传递&指针传递
1传值调用(实参不受影响,实参拷贝一份→传参[函数结束后被释放])
void exchange1(int x,int y)
{
int temp;
temp=x;
x=y;
y=temp;
}//无法实现xy的互换
2传址调用--指针传递
void exchange2(int *px,int *py)//传参=指针取值=所指向数据的地址
{
int temp=*px;
*px=*py;
*py=temp;
}
int a=4,b=5;
exchange2(&a,&b);
//将ab的地址传递给函数,对*px,*py的操作即是对a,b变量本身的操作。可以实现a,b的值交换
3.传址调用--引用传递
void exchange3(int &x,int &y)
{
int temp=x;
x=y;
y=temp;
}
int a=3,b=4;
exchange3(a,b);
// 引用传递是将变量的内存地址传递给方法,方法操作变量时会找到保存在该地址的变量,对其进行操作。会对原变量造成影响。
四、2/8/10/16进制
二进制(Binary):0-1,如 0110。用前缀0b表示(一说二进制不直接参与运算,没有前缀);用后缀 B 表示,如 0110 1001B。
八进制(Octal):0-7,满 8 进 1。用 前缀0 表示,如 076;另,用后缀 Q 表示(原是字母O,Octal,避免与数字0混淆),如 257Q 。
十进制(Decimal):1-9,满9进1。
十六进制(Hexadecimal):0-9, A-F,满 16 进 1,用 前缀0x 表示,如 0x5AF9;另,用后缀 H表示,如 AFH。
标签:0000,字节,int,1111,对齐,数据结构,原码
来源: https://blog.csdn.net/qq_42024067/article/details/100071371