数据类型 常量 补码 阶码
左值和右值:
左值必须要有内存实体,能放在赋值号左边的值
寄存器的数据一般都是右值,能放在赋值号右边的值
int num = 1;
num+1 的值不在内存,在寄存器里(CPU里)。绝对不能取寄存器地址。
#include <stdio.h>
int main()
{
int num = 3;
int data = 0;
_asm
{
mov eax, num //num移动到eax
add eax, 4
mov data, eax
}
printf("%d", data); //结果输出7
return 0;
}
cpu是处理计算的。
内存是存储的,内存不负责计算。
变量的赋值就算拷贝二进制。
内存之间不可以直接拷贝,必须通过CPU。
变量的值发生变化,就是变量的那一段内存,可以存放不同的二进制数据。
const的注意事项:
const int num; //错误的,常量必须初始化
const int num=20;//const常量只有在初始化的时候是左值
num = 30; //错误,不能被改变
如果要改变的话
const int num = 10;
int * p = (int *)#
*p = 3;
const define 定义常量的差别:
#define不会类型检查
const 会类型检查
#define N 10
const int M = 100; //伪常量
int a[N];//ok
int b[M];//不ok
赋值号会自动进行数据类型转换
#include <stdio.h>
#define M 10.0
const int N = 10.0;
int main()
{
printf("%d\n", M); // 0
printf("%d\n", N); // 10
return 0;
}
printf()的注意事项:
printf不会进行 数据类型转换,注意下面错误的例子
printf("%d", 10.0); // 0
printf("%d\n",10.3); // -1717986918
printf("%f\n",10); // 0.000000
printf连带效应,第一个错误,连带第二个错误
printf("%d\n%d\n", 10.0, 10); // 0 1076101120
类型不仅决定了大小,而且决定了二进制数据的解析方式
#include <stdio.h>
int main()
{
int num = 100;
int *p1 = #
float *p2 = #
double *p3 = #
printf("%d\n", *p1);
printf("%f\n", *p2);
printf("%f\n", *p3);
return 0;
}
数据类型的极限:
#include <stdio.h>
#include <limits.h>
#include <float.h>
int main()
{
printf("INT_MAX = %d\n", INT_MAX);
printf("INT_MIN = %d\n", INT_MIN);
printf("LONG_MAX = %ld\n", LONG_MAX); //32位平台,long和int最大值一样
printf("LONG_MIN = %ld\n", LONG_MIN);
printf("LLONG_MAX = %lld\n", LLONG_MAX);
printf("LLONG_MIN = %lld\n", LLONG_MIN);
printf("FLT_MAX = %.100f\n", FLT_MAX);
printf("FLT_MIN = %.100f\n", FLT_MIN);
printf("DBL_MAX = %.500f\n", DBL_MAX);
printf("DBL_MIN = %.500f\n", DBL_MIN);
return 0;
}
long long 和 long double
long long moblie = 18611210283;//老师手机号
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
输出只会根据格式解析对应的二进制:
#include <stdio.h>
#include <limits.h>
int main()
{
unsigned int num = -1;
int data = 4294967295;
printf("%d\n", num); //-1
printf("%d\n", data); //-1
printf("%u\n", num); //4294967295
printf("%u\n", data); //4294967295
return 0;
}
字节不同 数据之间的转换:
小字节转换为大字节数据的时候,有符号位就填充符号位
char ch = -1;
int num = ch;
printf("%d\n",num);//-1
无符号位就填充0
unsigned char ch = 3;
unsigned int num = ch;
printf("%d\n",num);//3
实数用阶码表示:
对于大小为32-bit的浮点数(32-bit为单精度,64-bit浮点数为双精度,80-bit为扩展精度浮点数),
1、其第31 bit为符号位,为0则表示正数,反之为-数,其读数值用s表示;
2、第30~23 bit为幂数,其读数值用e表示; 8位
3、第22~0 bit共23 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
内存检索:
_declspec(dllexport) void go()
{
void *p1 = 0xae0000;
void *p2 = 0xaef000;
for (char *p = p1; p != p2; p++)//内存最小单位是字节
{
int *px = p;//设定步长为4
if (*px == 90)
*px = 99;
}
}
位 与 运算符 &
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
异或可以实现交换数据的作用
#include <stdio.h>
int main()
{
char ch1 = 6;
char ch2 = 5;
ch1 ^= ch2;
ch2 ^= ch1;
ch1 ^= ch2;
printf("%d\n", ch1); // 5
printf("%d\n", ch2); // 6
return 0;
}
然而,这里面却存在着一个非常隐蔽的陷阱。
通常我们在对数组进行操作的时候,会交换数组中的两个元素,如exchang(&a[i], &b[j]), 这儿如果i==j了(这种情况是很可能发生的),得到的结果就并非我们所期望的。
异或可以指定 位进行反转:
对前四个反转,后四个保持原样
1010 0101 //前四个进行异或1 后四个进行异或0
//1111 0000
//0101 0101
位 取反 运算符 ~ 注意(!是逻辑取反)
char a = 240;
printf("%d\n", ~a); //15 位取反
printf("%d\n", !a); //0 逻辑取反
给出一个整数,计算出补码里有多少个1
while循环:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int get_num(int num)
{
int index = 0;
while (num)
{
num &= num - 1;
index++;
}
return index;
}
int main()
{
int num;
scanf("%u", &num);
printf("%d\n", get_num(num));
return 0;
}
for循环:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int get_num(int num)
{
int index = 0;
for (; num; num &= num - 1)
{
index++;
}
return index;
}
int main()
{
int num;
scanf("%u", &num);
printf("%d\n", get_num(num));
return 0;
}
goto循环:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int get_num(int num)
{
int index = 0;
AAAA:if (num)
{
num &= num - 1;
index++;
goto AAAA;
}
return index;
}
int main()
{
int num;
scanf("%u", &num);
printf("%d\n", get_num(num));
return 0;
}
递归:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int get_num(int num)
{
if (num == 0)
return 0;
return 1 + get_num(num & num - 1);
}
int main()
{
int num;
scanf("%u", &num);
printf("%d\n", get_num(num));
return 0;
}
给出一个整数,打印出来它的补码,原码,反码:
补码循环:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main()
{
int num;
scanf("%u", &num);
int data, i;
data = 1 << 31;
for (i = 1; i <= 32; i++)
{
printf("%c", num & data ? '1' : '0');
num <<= 1;
if (i % 4 == 0) putchar(' ');
}
return 0;
}
另外一种方法让data右移:注意是无符号unsigned:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main()
{
int num;
scanf("%u", &num);
unsigned int data, i;
data = 1 << 31;
for (i = 1; i <= 32; i++)
{
printf("%c", num & data ? '1' : '0');
data >>= 1;
if (i % 4 == 0) putchar(' ');
}
return 0;
}
//1111 1111 1111 1111 1001
//1000 0000 0000 0000 0000 补码递归:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
void buma(int num , int i)
{
if (i == 0)
return;
int data = 1 << 31;
if (i % 4 == 0) putchar(' ');
printf("%c", num & data ? '1' : '0');
num <<= 1;
i--;
buma(num, i);
}
int main()
{
int num;
scanf("%u", &num);
buma(num,32);
return 0;
}
原码循环:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main()
{
int num;
scanf("%u", &num);
int data, i;
data = 1 << 31;
if (num < 0)
{
num = ~num + 1;
num = num | data; //保证符号位是负的
}
for (i = 1; i <= 32; i++)
{
printf("%c", num & data ? '1' : '0');
num <<= 1;
if (i % 4 == 0) putchar(' ');
}
return 0;
}
原码递归:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
void yuanma(int num, int i)
{
if (i == 0)
return;
int data = 1 << 31;
if (i % 4 == 0) putchar(' ');
printf("%c", num & data ? '1' : '0');
num <<= 1;
i--;
yuanma(num, i);
}
int main()
{
int num;
scanf("%u", &num);
int data = 1 << 31;
if (num < 0)
{
num = ~num + 1;
num = num | data; //保证符号位是负的
}
yuanma(num, 32);
return 0;
}
反码循环:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main()
{
int num;
scanf("%u", &num);
int data, i;
data = 1 << 31;
if (num < 0)
{
num = num - 1;
num = num | data;
}
for (i = 1; i <= 32; i++)
{
printf("%c", num & data ? '1' : '0');
num <<= 1;
if (i % 4 == 0) putchar(' ');
}
return 0;
}
反码递归:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
void fanma(int num, int i)
{
if (i == 0)
return;
int data = 1 << 31;
if (i % 4 == 0) putchar(' ');
printf("%c", num & data ? '1' : '0');
num <<= 1;
i--;
fanma(num, i);
}
int main()
{
int num;
scanf("%u", &num);
int data = 1 << 31;
if (num < 0)
{
num = num - 1;
num = num | data;
}
fanma(num, 32);
return 0;
}