一、数据类型
基本数据类型
char
以下只是表示数值范围不同,字节数还是相同
unsigned char
signed char
short
unsigned short
signed short
int
unsigned int
signed int
long
unsigned long
signed long
float
double
构造类型:
数组
结构体 struct
枚举 enum
联合 union
指针类型:
int *pi;
char *pc;
float *pf;
void *pv;
空类型----->void
二、整型在内存中的存储
计算机符号数的基本概念
计算机有三种符号数,即为原码、反码、补码。
三种方法均有符号位和数值位两部分,符号位均为0正1负。
原码
将十进制直接转换位对应的二进制数
反码
原码符号位不变,其他位按位取反
补码
在求出反码的基础上,低位+1
正数的原码=反码=补码
对于整型来说,数据存放内存中其实存放的是补码(尤其用来表示负数)。因为使用补码,可以将符号位和数值域统一处理;因为CPU只有加法器,所以用补码表示可以统一加减法运算。
大端机和小端机
大端机(存储模式):数据低位保存在内存的高地址中,而数据的高位,保存在内存的低地址中
小端机(存储模式):数据低位保存在地址的低地址中,而数据的高位,保存在内存的高地址中。
int val = 1;
低位 高位
01 00 00 00
00 00 00 01
隐式类型的转换
若为大转小,则截断,如int->char,四个字节截成一个字节(往往截的是低位)。
若为小转大,则提升,即高位补位,若为无符号数则补0,若为有符号数则补符号位。char->int ,有符号数则补符号位。
unsigned char->int,无符号数则补0
注:提升看的是本身的类型,而不是要转的类型char->unsigned int,看本身,本身为有符号数(char),则补符号位,而不是看转成的类型(unsigned int)。
百度2015年系统工程师笔试题
请简述大端字节序和小端字节序的概念,设计一个小程序来判断当前机器的字节序。
//代码1
#include <stdio.h>
int check_sys()
{
int i = 1;
return (*(char *)&i);
}
int main()
{
int ret = check_sys();
if(ret == 1)
{
printf("小端\n");
}
else
{
printf("大端\n");
}
return 0;
}
代码中的 return (*(char *)&i);可以理解为:
int *pi = &i;
char *pc = pi;
char pt = *pc;
return pt;
练习
程序运行后会输出什么
①:
1
#include <stdio.h>
int main()
{
char a= -1;
signed char b=-1;
unsigned char c=-1;
printf("a=%d,b=%d,c=%d",a,b,c);
return 0;
}
分析:
分析代码可得,a,b,c均为char类型,1字节,在printf中,需要将他们转化为int类型进行打印,因此,就用到了隐式类型的转换,即小转大,即提升,看清a,b为有符号数,因此在提升时,补符号位,而c为无符号数,即高位补0。
因此程序运行的结果为-1,-1,255。
②、③:
2.
#include <stdio.h>
int main()
{
char a = -128;
printf("%u\n",a);
return 0;
}
3.
#include <stdio.h>
int main()
{
char a = 128;
printf("%u\n",a);
return 0;
}
分析代码可知,a为-128,它以补码的形式存储在计算机中,即11111111,11111111,11111111,10000000。题目要打印出unsigned int,即应该提升,因为本身类型为char,有符号数,则将表示数据的部分 10000000,进行提升,最高位补符号位,易知该数据的符号位为1,则提升的结果为11111111,11111111,11111111,10000000。打印的结果为232-1-127。
因为第3题也是取表示数值的部分进行提升,即10000000,因此打印的结果应和第二题的结果一样,均为232-1-127。
第2题结果如下:
第3题结果如下:
④:
4.
int i= -20;
unsigned int j = 10;
printf("%d\n", i+j);
//按照补码的形式进行运算,最后格式化成为有符号整数
分析:i 为int类型,j为unsigned int类型,虽然两者对应的字节一样,均为4Byte,但是表示的范围却不同,若要将两者相加,则需对 i 进行提升。
i = -20 ,其补码为:11111111,11111111,11111111,11101100
j=10,其补码为:00000000,00000000,00000000,00001010
将 i 中表示数值部分截取出来,进行提升,结果和其补码相同,则
i 11111111,11111111,11111111,11101100
+
j 00000000,00000000,00000000,00001010
= 11111111,11111111,11111111,11110110
数值部分化为原码为:10001010,符号位为1,则其数值为-10 。
⑤:
5.
unsigned int i;
for(i = 9; i >= 0; i--)
{
printf("%u\n",i);
}
按照正常思路,该程序运行后,打印出的结果应该为9,8,7,6,5,4,3,2,1,0。但是该程序运行后,打印的结果如下图:
会进入一个死循环。再来观察一下代码,可看出 i 的类型为unsigned int,unsigned int 代表着该数是一个无符号整数,即没有负数,结果均为正数,因此,当 i=0时,i- -;按逻辑 i 应该为-1,但是由于 i 是无符号整型,因此,在计算机中的补码为01111111,11111111,11111111,11111111,为正数。对应的结果为232-1即为图中的4294967295。因此会陷入死循环。
因此,得出有符号数的 0 - 1 = -1,无符号数的 0 - 1 = 232- 1 。
⑥
6.
char a[1000];
int i;
for(i=0; i<1000; i++)
{
a[i] = -1-i;
}
printf("%d",strlen(a));
首先,需知道strlen(a)遇到会一直遇到char数组的’\0’才会结束,’\0’表示空字符,二进制表示为0000,0000。因此,在for循环中,当-1 - i 的二进制为0000,0000时,该数组赋值就会结束,i 是int类型的数据,-1 - i 也是int 类型的数据,将一个int类型的数据赋值给char类型时,需要进行截断,即将表示4Byte截为1Byte。再分析可知,-1 - i = -1 +(-i),每次都是求 -i 的二进制数,然后加上-1的二进制数。
可看到,每次加-1的二进制数,结果会慢慢的靠近0000,0000。因此,要使1111,1111(255)全部变为0000,0000,总共需要255次。因此,程序打印的结果为255。
⑦
7.
unsigned char i = 0;
int main()
{
for(i = 0;i<=255;i++)
{
printf("hello world\n");
}
return 0;
}
分析代码可得,i 为 unsigned char 类型,即只有一个字节(1Byte),且为无符号数,代码 i= 0 中的0为字面常量,是int类型的,要将int 给 char 类型需要截断,因此 i = 0 的时,i 在计算机中表示为0000,0000,之后的每次+1,都是在截断之后进行+1操作,而 unsigned char 在计算机中的最大值为 1111,1111。,换算为10进制就是255,也就是说 i 的值最大取到255,但是跳出循环的条件时 i > 255,当 i 再次加1后,按逻辑来讲,结果为256,二进制为1,0000,0000,应该跳出循环,但char类型只有1Byte,因此,保留在 i 中的二进制为 0000,0000,结果变为0,不满足循环跳出的条件,继续循环。因此,该程序一旦运行就会造成无限的循环。