C常见基本数据类型

C常见基本数据类型 - 图1

带符号与无符号类型 signed和unsigned

  • int、stort long 都默认为带符号整型
  • signed 代表有符号,包括正数、负数和0,取值范围是-32768~32767
  • unsigned 代表无符号,只包括正数和0,取值范围是0~65535,要获得无符号类型必须指定该类型为unsigned,比如unsigned long。
  • signed、unsigned也可以修饰char,long还可以修饰double
  1. unsigned char c1 = 10;
  2. signed char c2 = -10;
  3. long double d1 = 12.0;

当然不同的编译器有不同的取值范围,其实signed和unsigned的区别就是它们的最高位是否要当做符号位,并不会像short和long那样改变数据的长度,即所占的字节数

不同编译器环境下基本数据类型的存储长度(字节)

  1. #include<stdio.h>
  2. #include<stdlib.h>
  3. int main() {
  4. printf("char \t\t size = %d\n", sizeof(char));
  5. printf("short \t\t size = %d\n", sizeof(short));
  6. printf("int \t\t size = %d\n", sizeof(int));
  7. printf("long\t\t size = %d\n", sizeof(long int));
  8. printf("long long\t size = %d\n", sizeof(long long));
  9. printf("float \t\t size = %d\n", sizeof(float));
  10. printf("double \t\t size = %d\n", sizeof(double));
  11. printf("long double\t size = %d\n", sizeof(long double));
  12. /*
  13. char size = 1
  14. short size = 2
  15. int size = 4
  16. long size = 4
  17. long long size = 8
  18. float size = 4
  19. double size = 8
  20. long double size = 8
  21. */
  22. system("pause");
  23. return 0;
  24. }
类型 32位 64位 取值范围 有效保留数字
char 1 1 -128 ~ 127
void*(指针变量) 4 8
short 2 2 -32768~32767,即 -215~(215-1)
unsigned short 2 2 0~65535,即 0~(216-1)
unsigned int 4 4 0~4294967295,即 0~ (232-1)
int 4 4 -2147483648 ~ 2147483647 , 即 -231~(231-1)
float 4 4 1.17549e-38 ~ 3.40282e+38 6~7位
double 8 8 1.79769e+308 ~ 2.22507e-308 15~16位
long double - 16 1.18973e+4932 ~ 3.3621e-4932 18~19位
long 4 8 -9223372036854775808 ~ 9223372036854775807
unsigned long 4 8 0 ~ 18446744073709551615
  • int、unsigned、long、unsigned long 、double的数量级最大都只能表示为10亿,即它们表示十进制的位数不超过10个,即可以保存所有9位整数。
  • short只是能表示5位;
  • 另外对于浮点说而言:使用double类型基本上不会有错。

在float类型中隐式的精度损失是不能忽视的,二双精度计算的代价相对于单精度可以忽略。

事实上,在有些机器上,double类型比float类型的计算要快得多。

float型只能保证6位有效数字,而double型至少可以保证15位有效数字(小数点后的数位),long double型提供的精度通常没有必要,而且还要承担额外的运行代价。

double是8字节共64位,其中小数位占52位,2-52=2.2204460492503130808472633361816e-16,量级为10-16,故能够保证2^-15的所有精度。

在有些机器上,用long类型进行计算所付出的运行时代价远远高于用int类型进行同样计算的代价,所以算则类型前要先了解程序的细节并且比较long类型与int类型的实际运行时性能代价。

  1. //c++
  2. #include<iostream>
  3. #include<string>
  4. #include <limits>
  5. using namespace std;
  6. int main()
  7. {
  8. cout << "type: \t\t" << "************size**************"<< endl;
  9. cout << "bool: \t\t" << "所占字节数:" << sizeof(bool);
  10. cout << "\t最大值:" << (numeric_limits<bool>::max)();
  11. cout << "\t\t最小值:" << (numeric_limits<bool>::min)() << endl;
  12. cout << "char: \t\t" << "所占字节数:" << sizeof(char);
  13. cout << "\t最大值:" << (numeric_limits<char>::max)();
  14. cout << "\t\t最小值:" << (numeric_limits<char>::min)() << endl;
  15. cout << "signed char: \t" << "所占字节数:" << sizeof(signed char);
  16. cout << "\t最大值:" << (numeric_limits<signed char>::max)();
  17. cout << "\t\t最小值:" << (numeric_limits<signed char>::min)() << endl;
  18. cout << "unsigned char: \t" << "所占字节数:" << sizeof(unsigned char);
  19. cout << "\t最大值:" << (numeric_limits<unsigned char>::max)();
  20. cout << "\t\t最小值:" << (numeric_limits<unsigned char>::min)() << endl;
  21. cout << "wchar_t: \t" << "所占字节数:" << sizeof(wchar_t);
  22. cout << "\t最大值:" << (numeric_limits<wchar_t>::max)();
  23. cout << "\t\t最小值:" << (numeric_limits<wchar_t>::min)() << endl;
  24. cout << "short: \t\t" << "所占字节数:" << sizeof(short);
  25. cout << "\t最大值:" << (numeric_limits<short>::max)();
  26. cout << "\t\t最小值:" << (numeric_limits<short>::min)() << endl;
  27. cout << "int: \t\t" << "所占字节数:" << sizeof(int);
  28. cout << "\t最大值:" << (numeric_limits<int>::max)();
  29. cout << "\t最小值:" << (numeric_limits<int>::min)() << endl;
  30. cout << "unsigned: \t" << "所占字节数:" << sizeof(unsigned);
  31. cout << "\t最大值:" << (numeric_limits<unsigned>::max)();
  32. cout << "\t最小值:" << (numeric_limits<unsigned>::min)() << endl;
  33. cout << "long: \t\t" << "所占字节数:" << sizeof(long);
  34. cout << "\t最大值:" << (numeric_limits<long>::max)();
  35. cout << "\t最小值:" << (numeric_limits<long>::min)() << endl;
  36. cout << "unsigned long: \t" << "所占字节数:" << sizeof(unsigned long);
  37. cout << "\t最大值:" << (numeric_limits<unsigned long>::max)();
  38. cout << "\t最小值:" << (numeric_limits<unsigned long>::min)() << endl;
  39. cout << "double: \t" << "所占字节数:" << sizeof(double);
  40. cout << "\t最大值:" << (numeric_limits<double>::max)();
  41. cout << "\t最小值:" << (numeric_limits<double>::min)() << endl;
  42. cout << "long double: \t" << "所占字节数:" << sizeof(long double);
  43. cout << "\t最大值:" << (numeric_limits<long double>::max)();
  44. cout << "\t最小值:" << (numeric_limits<long double>::min)() << endl;
  45. cout << "float: \t\t" << "所占字节数:" << sizeof(float);
  46. cout << "\t最大值:" << (numeric_limits<float>::max)();
  47. cout << "\t最小值:" << (numeric_limits<float>::min)() << endl;
  48. cout << "size_t: \t" << "所占字节数:" << sizeof(size_t);
  49. cout << "\t最大值:" << (numeric_limits<size_t>::max)();
  50. cout << "\t最小值:" << (numeric_limits<size_t>::min)() << endl;
  51. cout << "string: \t" << "所占字节数:" << sizeof(string) << endl;
  52. // << "\t最大值:" << (numeric_limits<string>::max)() << "\t最小值:" << (numeric_limits<string>::min)() << endl;
  53. cout << "type: \t\t" << "************size**************"<< endl;
  54. return 0;
  55. }

macOS输出结果:

  1. type: ************size**************
  2. bool: 所占字节数:1 最大值:1 最小值:0
  3. char: 所占字节数:1 最大值: 最小值:\200
  4. signed char: 所占字节数:1 最大值: 最小值:\200
  5. unsigned char: 所占字节数:1 最大值:\377 最小值:
  6. wchar_t: 所占字节数:4 最大值:2147483647 最小值:-2147483648
  7. short: 所占字节数:2 最大值:32767 最小值:-32768
  8. int: 所占字节数:4 最大值:2147483647 最小值:-2147483648
  9. unsigned: 所占字节数:4 最大值:4294967295 最小值:0
  10. long: 所占字节数:8 最大值:9223372036854775807 最小值:-9223372036854775808
  11. unsigned long: 所占字节数:8 最大值:18446744073709551615 最小值:0
  12. double: 所占字节数:8 最大值:1.79769e+308 最小值:2.22507e-308
  13. long double: 所占字节数:16 最大值:1.18973e+4932 最小值:3.3621e-4932
  14. float: 所占字节数:4 最大值:3.40282e+38 最小值:1.17549e-38
  15. size_t: 所占字节数:8 最大值:18446744073709551615 最小值:0
  16. string: 所占字节数:24
  17. type: ************size**************
  18. sh: pause: command not found
  19. Program ended with exit code: 0

数据类型转换

自动转换

自动转换发生在不同数据类型的量混合运算时,由编译系统自动完成。自动转换遵循以下规则:

  1. 若参与运算量的类型不同,则先转换成同一类型,然后进行运算。
  2. 转换按数据长度增加的方向进行,以保证精度不降低。如int型和long型运算时,先把int量转成long型后再进行运算。
  3. 所有的浮点运算都是以双精度进行的,即使仅含float单精度量运算的表达式,也要先转换成double型,再作运算。
  4. char型和short型参与运算时,必须先转换成int型。
  5. 在赋值运算中,赋值号两边量的数据类型不同时,赋值号右边量的类型将转换为左边量的类型。如果右边量的数据类型长度比左边长时,将丢失一部分数据,这样会降低精度,丢失的部分按四舍五入向前舍入。

下图表示了类型自动转换的规则:

  1. graph TD
  2. A[char shot]-->B
  3. B[int]-->C
  4. C[unsigned]-->D
  5. D[long]-->Double
  1. #include<stdio.h>
  2. int main(){
  3. float PI=3.14159;
  4. int s,r=5;
  5. s=r*r*PI;
  6. printf("s=%d\n",s);
  7. return 0;
  8. }

本例程序中,PI为实型;s,r为整型。在执行s=r_r_PI语句时,r和PI都转换成double型计算,结果也为double型。但由于s为整型,故赋值结果仍为整型,舍去了小数部分。

实型变量

在程序运行过程中可以改变其值的实型量被称为实型变量,实型变量分为:

  • 单精度(float)
  • 双精度(double)
  • 长双精度(long double)

强制类型转换

强制类型转换是通过类型转换运算来实现的。其一般形式为:

  1. (类型说明符) (表达式)

其功能是把表达式的运算结果强制转换成类型说明符所表示的类型。

例如:

  1. (float) a; /* 把a转换为实型 */
  2. (int)(x+y); /* 把x+y的结果转换为整型 */

在使用强制转换时应注意以下问题:

  • 类型说明符和表达式都必须加括号(单个变量可以不加括号),如把(int)(x+y)写成(int)x+y则成了把x转换成int型之后再与y相加了。
  • 无论是强制转换或是自动转换,都只是为了本次运算的需要而对变量的数据长度进行的临时性转换,而不改变数据说明时对该变量定义的类型。
  1. #include<stdio.h>
  2. int main(void){
  3. float f=5.75;
  4. printf("(int)f=%d,f=%f\n",(int)f,f);
  5. return 0;
  6. }

本例表明,f虽强制转为int型,但只在运算中起作用,是临时的,而f本身的类型并不改变。因此,(int)f的值为 5(删去了小数)而f的值仍为5.75。