您的位置:首页 > 编程语言 > C语言/C++

c语言数据类型、存取方式、类型转换

2019-04-15 14:41 120 查看

一、c语言的数据类型

1. 数据类型的意义:

(1) 为变量分配内存大小
(2) 规定这个变量的存取规则

2. 数据类型占用内存大小

每种数据类型,在不同的机器平台上占用内存是不同的。
32位CPU:

//整型
sizeof(char) = 1
sizeof(short) = 2
sizeof(int) = 4
sizeof(long) = 4
sizeof(long long) = 8
//指针
sizeof(char*) = 4
//浮点型
sizeof(float) = 4
sizeof(double) = 8

64位CPU:

//整型
sizeof(char) = 1
sizeof(short) = 2
sizeof(int) = 4
sizeof(long) = 8
sizeof(long long) = 8
sizeof(char*) = 8
sizeof(float) = 4
sizeof(double) = 8

32位与64位占用内存长度有区别的类型有:

long 	4 	8
char *	4	8
long double	12	16

3. 整形常量的表示形式:

十进制: 10,36
八进制(以数字0开头): 012
十六进制: 0x36

4. 有符号与无符号

对于char short int long等整形类型的数,都分有符号有无符号数。
而对于float和double这种浮点型数来说,只有有符号数,没有无符号数。
对于有符号数和无符号数来说,存储方式不同的。
对于float和double这种浮点类型的数,它在内存中的存储方式和整形数不一样。所以float和
int相比,虽然都是4字节,但是在内存中存储的方式完全不同。所以同一个4字节的内存,如果存储时是按照int存放的,取的时候一定要按照int型方式去取。如果存的时候和取的时候理解的方式不同,那数据就完全错了。

5. void关键字

C语言中的void类型,代表任意类型,而不是空的意思。任意类型的意思不是说想变成谁就变成谁,而是说它的类型是未知的,是还没指定的。
void * 是void类型的指针。void类型的指针的含义是:这是一个指针变量,该指针指向一个void类型的数。void类型的数就是说这个数有可能是int,也有可能是float,也有可能是个结构体,哪种类型都有可能,只是我当前不知道。
void型指针的作用就是,程序不知道那个变量的类型,但是程序员自己心里知道。程序员如何知道?当时给这个变量赋值的时候是什么类型,现在取的时候就还是什么类型。这些类型对不对,能否兼容,完全由程序员自己负责。编译器看到void就没办法帮你做类型检查了。

在函数的参数列表和返回值中,void代表的含义是:
一个函数形参列表为void,表示这个函数调用时不需要给它传参,如何传参,编译器会报错。
返回值类型是void,表示这个函数不会返回一个有意义的返回值。所以调用者也不要想着去使用该返回值。
不可以使用定义void类型的变量,因为编译器不知道分配多大内存,可以定义void*变量。
void *p = NULL;
int a = 0x203;
p = &a;
printf(“a = %d\n”, (int)p); //a = 515
printf(“a = %d\n”, (char)p); //a = 3
printf(“a = %f\n”, (float)p); //a = 0.000000

6. 常量后缀

问题描述:C/C++程序许多时候会看到一个常数后面会跟一个后缀说明,比如UL。常数后缀许多时候不用也不会有问题,只要考虑常数赋给变量时不溢出,因为变量进行计算时会将常数转换成自己的类型。但是有时候就是因为常数没有指定类型,而且数值很小(比如2)不会有溢出问题,也会产生很隐蔽的bug。比如有次将编译器选项的优化项选择为最高(那样源代码编译后生成的二进制文件会最小),在使用printf函数在LCD屏输出常数2时就出现了问题,输出的这个数字会不断改变,然后将该常数类型用后缀限定后,就一切正常了。所以在使用的编译器不是那么聪明,或者将编译器选项按照自己要求进行了修改后,程序中许多地方都要严格的进行书写。因为常数后缀在许多时候的关键作用,于是搜集资料进行了整理与学习。
数的进制:二进制数,八进制数(O),十进制数,十六进制数(0x)。程序中十进制数和十六进制数最为常见,八进制数很少见,二进制数只是一种表示(程序中并不能直接书写)。
整数常数后缀:u或U(unsigned)、l或L(long)、u/U与l/L的组合(如:ul、lu、Lu等),u和l没有顺序区别。例:100u; -123u; 0x123l。
浮点常数后缀:科学计数形式和小数点形式。浮点常数默认是double的。f或F(单精度浮点数)、l或L(长双精度浮点数)。(注:因浮点型常数总是有符号的,故没有u或U后缀)。例:1.23e5f; 1.23l; -123.45f。

unsigned long long laddr = 0xffffffffULL << 10;

二、各种数据类型的打印方式

http://c.biancheng.net/view/1793.html
http://c.biancheng.net/view/1758.html
http://c.biancheng.net/view/1760.html

三. 数据类型存取方式

分为整形存储 和 浮点型存储
存取方式上主要有两种,一种是整形一种是浮点型,这两种存取方式完全不同,没有任何关联,所以是绝对不能随意改变一个变量的存取方式。在整形和浮点型之内,譬如说4种整形char、short、int、long只是范围大小不同而已,存储方式是一模一样的。float和double存储原理是相同的,方式上有差异,导致了能表示的浮点型的范围和精度不同。

1. 整型存储方式

https://www.geek-share.com/detail/2502279623.html

2. 浮点型存储方式

https://www.geek-share.com/detail/2602947381.html
https://www.geek-share.com/detail/2607600717.html

int main()
{
float x = 1.0;
cout<<(int &)x<<endl;
cout<<*(int *)&x<<endl;
return 0;
}

我们发现输出结果均为1065353216

分析:
由于1.0为float型数据,占4字节,可以知道1.0在内存中存储为0 01111111 00000000000000000000000,
对于语句 *(int *)&x,意思就是说先将float型的x的指针强制转换为int型的指针,然后取出值。由于是按照
float型数据存储的,而却解释成int型,即对应的int整数为,而(int &)x就相当于*(int *)&x

四. 数据类型转换

0. int与char类型转换

1. int->char

从长字节数据类型转换为短字节数据类型,会产生截断:
如从4字节的int类型转换成1个字节的char类型,则取int数据的最低的一个字节,将这个字节的数据赋给char型数据。

2. char/unsigned char -> int

从char转换为int:则在前面的三个字节补符号位,即补上0xffffff(char的首位为1),或0x000000(char的首位为0),char的后一个字节保持不变复制给int。
从unsigned char转换为int,则前面补上0x000000.

int main()
{
int s=128;						//取s的最后一个字节给char  0x80
unsigned char unChar=s;			//unchar = 0x80
char Char=s;					//char = 0x80
printf("%x\t%x\n",Char,unChar);	//按16进制输出		//char转int 0xff ff ff 80  unchar转int 0x80
printf("%d\t%d\n",Char,unChar);	//按10进制输出
}

ffffff80	80
-128	128			//int类型 0xff ff ff 80就是-128

#include <stdio.h>
int main()
{
int s1,s2;
unsigned char unChar=128;		//int转unsigned char unchar = 0x80
char Char=128;					//int转char char = 0x80
s1=(int)unChar;					//unsigned char转int 补3个字节的0 0x80
s2=(int)Char;					//char转int,根据char符号位,补3个0xff或0x00 这里补0xff ff ff 80
printf("%x\t%x\n",s1,s2);//按16进制输出
printf("%d\t%d\n",s1,s2);//按10进制输出
}

80	ffffff80
128	-128

1. 整数与小数之间相互赋值

http://c.biancheng.net/view/1763.html

3. 数据类型转换

http://c.biancheng.net/view/1775.html
https://blog.csdn.net/SwordArcher/article/details/82351996
关于unsigned char、unsigned short使用printf(“%d”)进行输出的结果
关于short强制转换成int
short 和 int 类型的转换
相同数据类型运算不需要转换类型,但可能存在溢出。
a, b 都是unsigned int类型,做减法的时候不需类型转换。但a -b发生了溢出。

int
20000
main()
{
unsigned int a = 1, b = 2;
unsigned int c = a - b;
int c = a - b;
printf("c = %d\n", c);
printf("c = %u\n", c);
return 0;
}
c = -1
c = 4294967295

五、float类型比较

float类型只能精确到小数点以后前六位。所以无法比较更长的两个数是否相等,因为比较的话只会比较小数点以后前7位 是否相等。再长的话后面也不会比较了。
所以比较两个数是不是相等,可以比较a -b < 0.0000001 && a - b > -0.0000001 比较前7位

float a = 1.12345612;
float b = 1.12345623;
float c = 1.12345601;
float d = 1.12345613;

printf("a = %f, b = %f, a - b = %f, a - c = %f\n", a,  b, a - b, a - c);
printf("a == b ? %d  %d\n", a == b, a - b > -0.0000001 && a -b < 0.0000001);
printf("a == c ? %d %d \n", a == c, a - c > -0.0000001 && a - c < 0.0000001);
printf("a == d ? %d %d\n", a == d, (a - d > -0.0000001) && (a - d < 0.0000001));

float c1 = 0.00001, c2 = 0.0000001, c3 = 0.0000000123;
printf("c1 = %f, c2 = %f, c3 = %f\n", c1, c2, c3);

/*
root@lipenghui-virtual-machine:/mnt/hgfs/vmshare# ./test
a = 1.123456, b = 1.123456, a - b = -0.000000, a - c = 0.000000
a == b ? 0  0
a == c ? 0 0
a == d ? 1 1
c1 = 0.000010, c2 = 0.000000, c3 = 0.000000
*/

float和0比较,可以这样
if (a > -0.0000001 && a < 0.0000001)

六、float类型0在内存中的存储

+0,-0 为特殊编码 ,+0 每一位都是0,-0 除了符号位是1,其余都是0
float a =0.0;
printf(“0x%08x”,*(int *)&a);

int main()
{
float a = 1.0;
cout << (int)a << endl;
cout << (int&)a << endl;

a = 0.0;
cout << (int)a << endl;
cout << (int&)a << endl;

a = +0.0;
cout << (int)a << endl;
cout << (int&)a << endl;

a = -0.0;
cout << (int)a << endl;
cout << (int&)a << endl;
return 0;
}
1
1065353216

0
0

0
0

0
-2147483648

七、位域

http://m.biancheng.net/view/2037.html
位域的压缩:
linux下位域是压缩存放的,前面的类型只是限制后面的长度不能超过这个类型的长度,对于数据的存放占用大小是没有影响的,数据存放内存占用大小只与后面的位域宽度有关。结构体中出现了位域,各个数据之间都会压缩着存放。

struct test
{
short a:5;
char :4;
int b:3;			//前面3个一起占用12位,2个字节
char d;
char f;			//总共4个字节
};
struct bs{
unsigned m: 12;		//占两12位,2个字节,而不会是int类型的4个字节
unsigned short ch;
unsigned char ch2;
unsigned p: 4;		//占两4位,1个字节,而不会是int类型的4个字节
unsigned char ch3;
};
int main()
{
cout << sizeof(test) << endl;		//4
cout << sizeof(bs) << endl;			//8
return 0;
}

但位域的类型会对最后的结构体对齐长度有影响

struct bs{
char b1:5;
unsigned short ch:2;
unsigned int ch2:2;			//4
};
struct bs2{
char b1:5;
unsigned short ch:2;
unsigned short ch2:2;		//2
};

struct bs{
char b1:3;
unsigned char ch2:2;		//1
};
struct bs2{
char b1:3;
unsigned short ch2:2;		//2
};
struct bs3{
char b1:3;
unsigned ch2:2;				//4
};
struct bs4{
char b1:3;
unsigned char ch2:2;
char b2;					//2
};
struct bs5{
char b1:3;
unsigned short ch2:2;		//2
char b2;
};
struct bs6{
char b1:3;
unsigned ch2:2;				//4
char b2;
};
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: