1、判断下面的程序输出什么?
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdlib.h>
int main()
{
char a = -1;
signed char b = -1;
unsigned char c = -1;
printf("a=%d\nb=%d\nc=%d\n", a, b, c);
system("pause");
return 0;
}
规则:
原码→反码:除符号位,按位取反; 反码→补码:反码加一
先看-1在内存中是怎么存的:
-1的原码: 1000 0000 0000 0000 0000 0000 0000 0001
-1的反码: 1111 1111 1111 1111 1111 1111 1111 1110
-1的补码: 1111 1111 1111 1111 1111 1111 1111 1111 (内存)
打印a:
补码截断:
char类型占一个字节,8位;
-1的补码:1111 1111 1111 1111 1111 1111 1111 1111 截断后8位(第一个字节)赋给字符型a;
由于a要以%d形式打印,所以将char型提升为int型;
整形提升:
概念:
无符号类型 提升 补0;
有符号类型 提升 高位为1,补1;高位为0,补0
此时, a是char型,有符号类型。
1111 1111 提升给 a:
因为高位(最左边一位)为1,所以给a的前24位(共4个字节32位)补1:
1111 1111 1111 1111 1111 1111 1111 1111(内存中存的是二进制补码)
运行结果是以原码的形式打印出来的,求出原码:
补码:1111 1111 1111 1111 1111 1111 1111 1111
反码:1111 1111 1111 1111 1111 1111 1111 1110
原码:1000 0000 0000 0000 0000 0000 0000 0001(-1)
所以,a打印结果是:-1
打印b:
signed char类型和char类型在这里是一样的截断方式和整形提升,同上:
所以,b打印结果是:-1
打印c:
unsigned char 与char都是占用1个字节,阶段后8位;
1111 1111 提升给 c:
整形提升:
unsigned char 类型,无符号。c的前24位补0:
0000 0000 0000 0000 0000 0000 1111 1111(内存中存的是二进制补码)
符号位是0,原码和补码相同:
0000 0000 0000 0000 0000 0000 1111 1111(原码:255)
所以,c打印结果是:255
运行结果:
2、我们用的笔记本一般是大端机还是小端机?
我们先来了解一下什么是大端和小端:
大端:数据的低位保存在内存的高地址中;数据的高位保存在内存的低地址中。
小端:数据的低位保存在内存的低地址中;数据的高位保存在内存的高地址中。
我们常用的x86结构就是小端模式。
如何判断大小端机呢?简单说一下这3中方式:
1、取低地址,解引用判断
int main()
{
int x = 1;
char* p = (char*) &x; // 截断,取x的低地址
if (*p == 1) // 看1是否存在低地址
printf("小端机\n");
else
printf("大端机\n");
}
2、强制类型转换判断:
int main()
{
int x = 1;
char flag = (char) x;
if (flag == 1)
printf("小端机\n");
else
printf("大端机\n");
}
3、联合体/共用体:
union(联合体/共用体)的各个成员是以同一个地址开始存放的,每一个时刻只可以存储一个成员,这样就要求它在分配内存单元时候要满足两点:
1.一般而言,共用体类型实际占用存储空间为其最长的成员所占的存储空间;
2.若是该最长的存储空间对其他成员的元类型(如果是数组,取其类型的数据长度,例int a[5]为4)不满足整除关系,该最大空间自动延伸;
int check()
{
union UN
{
int i;
char c;
};
union UN test;
test.i = 1;
return test.c;
}
int main()
{
if(check()==1)
printf("小端机\n");
else
printf("大端机\n");
return 0;
}