首页 > 代码库 > 9.17 数据类型 常量 补码 阶码

9.17 数据类型 常量 补码 阶码

左值和右值:

左值必须要有内存实体,能放在赋值号左边的值
寄存器的数据一般都是右值,能放在赋值号右边的值

int num = 1;
num+1  的值不在内存,在寄存器里(CPU里)。绝对不能取寄存器地址。
  1. #include <stdio.h>
  2. int main()
  3. {
  4. int num = 3;
  5. int data = 0;
  6. _asm
  7. {
  8. mov eax, num //num移动到eax
  9. add eax, 4
  10. mov data, eax
  11. }
  12. printf("%d", data); //结果输出7
  13. return 0;
  14. }

cpu是处理计算的。
内存是存储的,内存不负责计算。

变量的赋值就算拷贝二进制。
内存之间不可以直接拷贝,必须通过CPU。

变量的值发生变化,就是变量的那一段内存,可以存放不同的二进制数据。


const的注意事项:

const int num; //错误的,常量必须初始化


const int num=20;//const常量只有在初始化的时候是左值
num = 30;              //错误,不能被改变


如果要改变的话
const int num = 10;
int * p = (int *)&num;
*p = 3;


const  define 定义常量的差别:

#define不会类型检查
const  会类型检查



#define N 10
const int M = 100;    //伪常量

int a[N];//ok
int b[M];//不ok


赋值号会自动进行数据类型转换
  1. #include <stdio.h>
  2. #define M 10.0
  3. const int N = 10.0;
  4. int main()
  5. {
  6. printf("%d\n", M); // 0
  7. printf("%d\n", N); // 10
  8. return 0;
  9. }

printf()的注意事项:

printf不会进行 数据类型转换,注意下面错误的例子
  1. printf("%d", 10.0);    //  0 
  2. printf("%d\n",10.3);  // -1717986918
  3. printf("%f\n",10);        // 0.000000 

printf连带效应,第一个错误,连带第二个错误
  1. printf("%d\n%d\n", 10.0, 10);  //  0          1076101120 

类型不仅决定了大小,而且决定了二进制数据的解析方式
  1. #include <stdio.h>
  2. int main()
  3. {
  4. int num = 100;
  5. int *p1 = &num;
  6. float *p2 = &num;
  7. double *p3 = &num;
  8. printf("%d\n", *p1);
  9. printf("%f\n", *p2);
  10. printf("%f\n", *p3);
  11. return 0;
  12. }



数据类型的极限:
  1. #include <stdio.h>
  2. #include <limits.h>
  3. #include <float.h>
  4. int main()
  5. {
  6. printf("INT_MAX = %d\n", INT_MAX);
  7. printf("INT_MIN = %d\n", INT_MIN);
  8. printf("LONG_MAX = %ld\n", LONG_MAX); //32位平台,long和int最大值一样
  9. printf("LONG_MIN = %ld\n", LONG_MIN);
  10. printf("LLONG_MAX = %lld\n", LLONG_MAX);
  11. printf("LLONG_MIN = %lld\n", LLONG_MIN);
  12. printf("FLT_MAX = %.100f\n", FLT_MAX);
  13. printf("FLT_MIN = %.100f\n", FLT_MIN);
  14. printf("DBL_MAX = %.500f\n", DBL_MAX);
  15. printf("DBL_MIN = %.500f\n", DBL_MIN);
  16. return 0;
  17. }


 
long long    和    long  double
  1. long long moblie = 18611210283;//老师手机号
  2. printf("%lld", moblie);
long long 占  8个字节  主要是为了存储手机号~qq号


整数的补码:

有符号整数

0(+0    -0)
0000    0000    0000    0000


+1
0000    0000    0000    0001

-1
1111    1111    1111    1111


+2147483637       
0111    1111    1111   1111

-2147483638
1000     0000    0000     0000



无符号整数
+4294967295
1111   1111    1111     1111


输出只会根据格式解析对应的二进制:
  1. #include <stdio.h>
  2. #include <limits.h>
  3. int main()
  4. {
  5. unsigned int num = -1;
  6. int data = 4294967295;
  7. printf("%d\n", num); //-1
  8. printf("%d\n", data); //-1
  9. printf("%u\n", num); //4294967295
  10. printf("%u\n", data); //4294967295
  11. return 0;
  12. }


字节不同 数据之间的转换:

小字节转换为大字节数据的时候,有符号位就填充符号位
  1. char ch = -1;
  2. int num = ch;
  3. printf("%d\n",num);//-1

无符号位就填充0
  1. unsigned char ch = 3;
  2. unsigned int num = ch;
  3. printf("%d\n",num);//3


实数用阶码表示:

对于大小为32-bit的浮点数(32-bit为单精度,64-bit浮点数为双精度,80-bit为扩展精度浮点数),  
1、其第31 bit为符号位,为0则表示正数,反之为-数,其读数值用s表示;  
2、第3023 bit为幂数,其读数值用e表示;  8

3、第220 bit23 bit作为系数,视为二进制纯小数,假定该小数的十进制值为x  


41200000        10.0
0100 0001 0           010 0000         0000 0000 0000 0000

c1200000         -10.0
1100 0001 0           010 0000         0000 0000 0000 0000

4124cccd          10.3
0100 0001 0          010 0100         1100 1100 1100 1101

40ebced9         7.369
0100 0000 1         110 1011        1100  1110  1101  1001

内存检索:

  1. _declspec(dllexport) void go()
  2. {
  3. void *p1 = 0xae0000;
  4. void *p2 = 0xaef000;
  5. for (char *p = p1; p != p2; p++)//内存最小单位是字节
  6. {
  7. int *px = p;//设定步长为4
  8. if (*px == 90)
  9. *px = 99;
  10. }
  11. }

位  与  运算符  &

1和0    对  1  相与  都是原来的值              1 & 1  = 1    0 & 1 = 0

1和0    对  0  相与  都会变成0                    1 & 0  = 0    0 & 0 = 0                       和0相与可以用来关灯


位  或   运算符   |

1和0    对  1  相或  都会变成1                    1 | 1  = 1            0 |  1 = 1                   和1相或 可以用来开灯

1和0    对  0  相或 都是原来的值                1 | 0  = 1             0 | 0 = 0          

位 异或  运算符  ^
相同为0     不同为1,      搞基即变0

1和0    对  1   异或      都会发生改变    1  ^   1    =  0             0  ^  1    =  1                只要和1异或     值都会发生改变

1和0    对  0   异或      都是原来的值    1   ^   0   =  1            0   ^  0     = 0


异或可以实现交换数据的作用
  1. #include <stdio.h>
  2. int main()
  3. {
  4. char ch1 = 6;
  5. char ch2 = 5;
  6. ch1 ^= ch2;
  7. ch2 ^= ch1;
  8. ch1 ^= ch2;
  9. printf("%d\n", ch1); // 5
  10. printf("%d\n", ch2); // 6
  11. return 0;
  12. }
然而,这里面却存在着一个非常隐蔽的陷阱。
通常我们在对数组进行操作的时候,会交换数组中的两个元素,如exchang(&a[i], &b[j]), 这儿如果i==j了(这种情况是很可能发生的),得到的结果就并非我们所期望的。


异或可以指定 位进行反转:

对前四个反转,后四个保持原样
 1010       0101   //前四个进行异或1  后四个进行异或0     
//1111     0000 
//0101     0101



位  取反  运算符 ~    注意(!是逻辑取反)
  1. char a = 240;
  2. printf("%d\n", ~a); //15 位取反
  3. printf("%d\n", !a); //0 逻辑取反



给出一个整数,计算出补码里有多少个1

while循环:
  1. #define _CRT_SECURE_NO_WARNINGS
  2. #include <stdio.h>
  3. int get_num(int num)
  4. {
  5. int index = 0;
  6. while (num)
  7. {
  8. num &= num - 1;
  9. index++;
  10. }
  11. return index;
  12. }
  13. int main()
  14. {
  15. int num;
  16. scanf("%u", &num);
  17. printf("%d\n", get_num(num));
  18. return 0;
  19. }

for循环:
  1. #define _CRT_SECURE_NO_WARNINGS
  2. #include <stdio.h>
  3. int get_num(int num)
  4. {
  5. int index = 0;
  6. for (; num; num &= num - 1)
  7. {
  8. index++;
  9. }
  10. return index;
  11. }
  12. int main()
  13. {
  14. int num;
  15. scanf("%u", &num);
  16. printf("%d\n", get_num(num));
  17. return 0;
  18. }
goto循环:
  1. #define _CRT_SECURE_NO_WARNINGS
  2. #include <stdio.h>
  3. int get_num(int num)
  4. {
  5. int index = 0;
  6. AAAA:if (num)
  7. {
  8. num &= num - 1;
  9. index++;
  10. goto AAAA;
  11. }
  12. return index;
  13. }
  14. int main()
  15. {
  16. int num;
  17. scanf("%u", &num);
  18. printf("%d\n", get_num(num));
  19. return 0;
  20. }
递归:
  1. #define _CRT_SECURE_NO_WARNINGS
  2. #include <stdio.h>
  3. int get_num(int num)
  4. {
  5. if (num == 0)
  6. return 0;
  7. return 1 + get_num(num & num - 1);
  8. }
  9. int main()
  10. {
  11. int num;
  12. scanf("%u", &num);
  13. printf("%d\n", get_num(num));
  14. return 0;
  15. }


给出一个整数,打印出来它的补码,原码,反码:

补码循环:
  1. #define _CRT_SECURE_NO_WARNINGS
  2. #include <stdio.h>
  3. int main()
  4. {
  5. int num;
  6. scanf("%u", &num);
  7. int data, i;
  8. data = 1 << 31;
  9. for (i = 1; i <= 32; i++)
  10. {
  11. printf("%c", num & data ? ‘1‘ : ‘0‘);
  12. num <<= 1;
  13. if (i % 4 == 0) putchar(‘ ‘);
  14. }
  15. return 0;
  16. }

另外一种方法让data右移:注意是无符号unsigned:
  1. #define _CRT_SECURE_NO_WARNINGS
  2. #include <stdio.h>
  3. int main()
  4. {
  5. int num;
  6. scanf("%u", &num);
  7. unsigned int data, i;
  8. data = 1 << 31;
  9. for (i = 1; i <= 32; i++)
  10. {
  11. printf("%c", num & data ? ‘1‘ : ‘0‘);
  12. data >>= 1;
  13. if (i % 4 == 0) putchar(‘ ‘);
  14. }
  15. return 0;
  16. }
//1111 1111 1111 1111 1001
//1000 0000 0000 0000 0000  



补码递归:
  1. #define _CRT_SECURE_NO_WARNINGS
  2. #include <stdio.h>
  3. void buma(int num , int i)
  4. {
  5. if (i == 0)
  6. return;
  7. int data = 1 << 31;
  8. if (i % 4 == 0) putchar(‘ ‘);
  9. printf("%c", num & data ? ‘1‘ : ‘0‘);
  10. num <<= 1;
  11. i--;
  12. buma(num, i);
  13. }
  14. int main()
  15. {
  16. int num;
  17. scanf("%u", &num);
  18. buma(num,32);
  19. return 0;
  20. }


原码循环:
  1. #define _CRT_SECURE_NO_WARNINGS
  2. #include <stdio.h>
  3. int main()
  4. {
  5. int num;
  6. scanf("%u", &num);
  7. int data, i;
  8. data = 1 << 31;
  9. if (num < 0)
  10. {
  11. num = ~num + 1;
  12. num = num | data; //保证符号位是负的
  13. }
  14. for (i = 1; i <= 32; i++)
  15. {
  16. printf("%c", num & data ? ‘1‘ : ‘0‘);
  17. num <<= 1;
  18. if (i % 4 == 0) putchar(‘ ‘);
  19. }
  20. return 0;
  21. }
原码递归:
  1. #define _CRT_SECURE_NO_WARNINGS
  2. #include <stdio.h>
  3. void yuanma(int num, int i)
  4. {
  5. if (i == 0)
  6. return;
  7. int data = 1 << 31;
  8. if (i % 4 == 0) putchar(‘ ‘);
  9. printf("%c", num & data ? ‘1‘ : ‘0‘);
  10. num <<= 1;
  11. i--;
  12. yuanma(num, i);
  13. }
  14. int main()
  15. {
  16. int num;
  17. scanf("%u", &num);
  18. int data = 1 << 31;
  19. if (num < 0)
  20. {
  21. num = ~num + 1;
  22. num = num | data; //保证符号位是负的
  23. }
  24. yuanma(num, 32);
  25. return 0;
  26. }


反码循环:
  1. #define _CRT_SECURE_NO_WARNINGS
  2. #include <stdio.h>
  3. int main()
  4. {
  5. int num;
  6. scanf("%u", &num);
  7. int data, i;
  8. data = 1 << 31;
  9. if (num < 0)
  10. {
  11. num = num - 1;
  12. num = num | data;
  13. }
  14. for (i = 1; i <= 32; i++)
  15. {
  16. printf("%c", num & data ? ‘1‘ : ‘0‘);
  17. num <<= 1;
  18. if (i % 4 == 0) putchar(‘ ‘);
  19. }
  20. return 0;
  21. }
反码递归:
  1. #define _CRT_SECURE_NO_WARNINGS
  2. #include <stdio.h>
  3. void fanma(int num, int i)
  4. {
  5. if (i == 0)
  6. return;
  7. int data = 1 << 31;
  8. if (i % 4 == 0) putchar(‘ ‘);
  9. printf("%c", num & data ? ‘1‘ : ‘0‘);
  10. num <<= 1;
  11. i--;
  12. fanma(num, i);
  13. }
  14. int main()
  15. {
  16. int num;
  17. scanf("%u", &num);
  18. int data = 1 << 31;
  19. if (num < 0)
  20. {
  21. num = num - 1;
  22. num = num | data;
  23. }
  24. fanma(num, 32);
  25. return 0;
  26. }



来自为知笔记(Wiz)


9.17 数据类型 常量 补码 阶码