基本类型
数据类型:
1.char(字符类型通常归类于整形)
short
int(在16位平台下的大小是2;在32位平台下的大小是4,在64位平台下大小也为4)
long(对long的大小要求是>=4可以是4,可以是8)
long long(只有在C99标准下才支持)(不一定准确,我在Linux C89 下测试了)
float
double
C89的基本类型,C99之后又增加了许多类型,如下图:
bool(_Bool):布尔类型(C99)
不过在C语言中0为假非0为真,在C语言可以没有布尔类型
整形家族:
char(不等价于signed char)(取决于编译器)(常见的编译器等价于signed char):signed char(有符号字符) unsigned char(无符号字符)
int(整型): singed int unsinged int(无符号数即使用负数赋值,它也是个正数)
short [int](短整型):unsigned short signed short
long [int](长整型):unsigned long signedlong
浮点型类型
float(单精度浮点数,占4个字节),double(双精度浮点数,占8个字节)如果创建的数对精度要求比较高可以用double
构造类型(自定义类型)
数组类型(自定义类型):int [5],int [10],char [5]
结构体类型(自定义类型)
枚举类型(自定义类型)
联合类型(自定义类型)
指针类型
char *pc;
int * pi;
float *pf;
void *pv
void 意为空类型或无类型;通常用于函数返回类型,函数的参数,指针类型
整型在内存中的存储
内存中的数据的真实排布,是以十六进制的形式展示的
右侧的乱码是内存中的数据翻译成文本,没有特别大的考虑意义
整数的二进制的三种表现形式:
源码,反码,补码
而内存中存的是补码
正数的源码,反码,补码是相同的
负数:
源码:按照二进制直接写就是原码
反码: 符号位不变,其它位按位取反
补码:反码的二进制序列加1就是补码
~与反码的不同:~是连符号位都按位取反(每个位都按位取反)
为什么整数在内存中存的都是补码?
1 - 1可以写为1 +(-1)
大小端字节序
大端字节序存储:数据的低权值(数据的大数位)位放在高地址处,高权值位放在低地址处
小端字节序存储:数据的高权值位放在高地址处,低权值位放在高地址处
为什么会有大小端?
为什么会有大小端模式之分呢?这是因为在计算机系统中,我们是以字节为单位的,每个地址单元都对应着一个字节,一个字节为8 bit。但是在C语言中除了8 bit的char之外,还有16 bit的short 型,32 bit的long型(要看具体的编译器),另外,对于位数大于8位的处理器,例如16位或者32位的处理器,由于寄存器宽度大于一个字节,那么必然存在着一个如何将多个字节安排的问题。因此就导致了大端存储模式和小端存储模式。例如:一个 16bit 的 short 型 x ,在内存中的地址为 0x0010 , x 的值为 0x1122 ,那么 0x11 为 高字节, 0x22 为低字节。对于大端模式,就将 0x11 放在低地址中,即 0x0010 中, 0x22 放在高地址中,即 0x0011 中。小端模式,刚好相反。我们常用的 X86 结构是小端模式,而 KEIL C51 则为大端模式。很多的ARM,DSP都为小端模式。有些ARM处理器还可以由硬件来选择是大端模式还是小端模式。
百度系统工程师面试题:
什么是大小端,如何验证大小端?
大端字节序存储:数据的低权值(数据的大数位)位放在高地址处,高权值位放在低地址处
小端字节序存储:数据的高权值位放在高地址处,低权值位放在高地址处
代码如下:
#include<stdio.h>
#include<stdbool.h>
int main()
{
int a = 1;
char* p = (char*)&a;
if (*p == 1)
{
printf("小端\n");
}
else
{
printf("大端\n");
}
return 0;
}
练习
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都输出到屏幕上,以(整数)%d的形式打印,要发生整形提升,char a 默认有符号位(VS2019),整形提升是补1(内存中的补码),因此a和b整形提升后内存中的值是11111111111111111111111111111111(补码)即为-1,c为无符号char,整形提升默认要补0,内存存储的是00000000000000000000000011111111(补码),因此c为255.
2.
#include <stdio.h>
int main()
{
char a = -128;
printf("%u\n",a);
return 0;
}
char a=-128;在内存中是10000000;整形提升补1,即11111111111111111111111110000000
3.
#include <stdio.h>
int main()
{
char a = 128;
printf("%u\n",a);
return 0;
}
128放在char a变量中存储在内存中也是1000 0000,整形提升后也是11111111111111111111111110000000.
4.
int i= -20;
unsigned int j = 10;
printf("%d\n", i+j);
//按照补码的形式进行运算,最后格式化成为有符号整数
i发生算术转换后,补码相加结果再以有符号整数的结果打印出来,故为-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是无符号数,因此比较始终认为i>=0;
6.
int main()
{
char a[1000];
int i;
for(i=0; i<1000; i++)
{
a[i] = -1-i;
}
printf("%d",strlen(a));
return 0;
}
255,-1的补码11111111,-2的补码11111110,-3的补码11111101,,直到最后会变为00000000;strlen计算的是11111111到00000001的数,遇到00000000停止。
7.
#include <stdio.h>
unsigned char i = 0;
int main()
{
for(i = 0;i<=255;i++)
{
printf("hello world\n");
}
return 0;
}
死循环的打印hello world。