1.整型
- 概念:表达整数类型的数据
- 语法:
int a = 123; // 定义了一个专门用来存储整数的变量a
a = 456 ;
- 需要注意的地方:
- int 的本意是 integer,即整数的意思
- int a 代表在内存中开辟一块小区域,称为 a,用来存放整数,a 一般被称为变量(他的值可以被改变)。
- 变量 a 所占内存大小,在不同的系统中是不一样的,64位 、 32位 系统典型的大小是4个字节
- 变量 a 有固定的大小,因此也有取值范围,典型的范围是:-2147483648到2147483647
- int Max = 50 ;
- 整型修饰符
- short:用来缩短整型变量的尺寸,减少取值范围并节省内存,称为短整型, (32位、64位)它会使得整形变为原本的一半
- long:用来增长整型变量的尺寸,增大取值范围并占用更多内存,称为长整型,(64位)它会使得整形从原本的4字节增加到8字节。
- long long:用来增长整型变量的尺寸,增大取值范围并占用更多内存,称为长长整型 (32位)系统中使得整型从4字节提升位8字节。
- unsigned:用来去除整型变量的符号位,使得整型变量只能表达非负整数
short int a; // 短整型 32 、 64 位系统中 尺寸为 2字节
long int b; // 长整型 32位系统中尺寸位 4字节 64位系统中尺寸位 8字节
long long int c; // 长长整型 32位系统中尺寸位 8字节 64位系统中尺寸位 8字节
unsigned int e; // 无符号整型 所占的内存大小不变,只不过不需要描述正负符号,因此他只能表达正整数
unsigned short int f; // 无符号短整型
unsigned long int g; // 无符号长整型
unsigned long long int h; // 无符号长长整型
- 使用整型修饰符后,关键字 int 可以被省略:
- 这些修饰符默认用于修饰整型类型,因此省略后它依然表示一种整型
short a; // 短整型
long b; // 长整型
long long c; // 长长整型
unsigned e; // 无符号整型
unsigned short f; // 无符号短整型
unsigned long g; // 无符号长整型
unsigned long long h; // 无符号长长整型
- 符号位:
- 符号位位于整数类型的二进制位中最高的一位
- 有符号的整型数据,首位(最高位)为符号位,0表示正数,1表示负数。
- 无符号的整形数据,没有符号位。
- 溢出:
-
- 超过数据所能表达的范围,称为溢出,就像汽车里程表,最大值和最小值是相邻的
- 编码形式:
-
- 原码:正数直接使用二进制来表达,比如a=100,在内存中是 00…001100100
- 补码:负数用绝对值取反加一来表达,比如a=-3,在内存中是11…1111111101
- 补码 = 源码 --> 取反 --> 加1
-
- 注意负数的补码在取反加一的时候,符号位是不动的
- 进制:源码中可以使用八进制、十进制或十六进制,但实际数据在内存中一律是二进制
-
- 十进制(默认),比如1099
- 八进制,比如013 , 八进制的前缀就是 0
- 十六进制,比如0x6FF0A , 十六进制的前缀是 0x 或 0X
- 格式控制符
- int 整型:%d
- int 整型:%u 以无符号为解析规则
- short 整型:%hd, h代表half,即一半的存储字节
- long 整型:%ld
- long long 整型:%lld
- 显示不同进制的前缀: %#o、 %#x
2.浮点型(实型)
- 概念:用来表达实数的数据类型
- 分类:
- 单精度浮点型(float),典型尺寸是4字节
- 双精度浮点型(double),典型尺寸是8字节
- 长双精度浮点型(long double),典型尺寸是16字节
- 占用内存越多,能表达的精度越高
float f1; // 单精度
double f2; // 双精度
long double f3; // 长双精度
3.字符
实际上是一个单字节的整型,能参与任何整型可以参与的运算和操作。
char ch1 = 'a'; // 'a'是字符常量,代表字母a
char ch2 = '\n'; // '\n'是不可见字符常量,代表回车
计算机中存储的都是1和0,因此各种字符都必须被映射为某个数字才能存储到计算机中,这种映射关系形成的表称为 ASCII 码表。
字符本质上就是一个单字节的整型,支持整型所有的运算。比如:
char c1 = 20;
char c2 = c1 + 'a'; // 等价于 char c2 = 20 + 97;
printf("%c\n", c2); // 以字符形式输出117,即 'u'
printf("%d\n", c2); // 以整型形式输出117
4.字符串
- 定义
// 字符串的定义方式有两种:指针和数组
char *s1 = "abcd"; // 使用字符指针来表示字符串 (使用指针s1来【指向】字符串"abcd"的地址)
char s2[]= "abcd"; // 使用字符数组来表示字符串 (使用一个数组s2来【存放】了"abcd"这些字符数据)
// 注意,使用数组来定义字符串时,方括号[]里面的数字可以省略
// 不省略也可以,但必须必字符串实际占用的内存字节数要大,比如:
char s3[] = "apple";
char s4[5] = "apple"; // "apple" 隐藏了一个结束符'\0' 因此该数组为 字符数组
char s5[6] = "apple"; // 正确写法必须大于等于6
- 在内存中的存储
- 在内存中实际上是多个连续字符的组合
- 任何字符串都以一个 ‘\0’ 作为结束标记,例如:“funny story” 的内存如下
数组表示字符串是把字符串常量直接复制一份过来,可访问可修改
指针是指向字符串的地址,因为是字符串常量,所以只可访问不可修改
5.布尔型数据
- 概念:布尔型数据只有真、假两种取值,非零为真,零为假。
- 语法:
bool a = 1; // true 逻辑真,此处1可以取其他任何非零数值
bool b = 0; // false 逻辑假
- 注意:
- 逻辑真除了 1 之外,其他任何非零数值都表示逻辑真,等价于 1。
- 使用布尔型 bool 定义变量时需要包含系统头文件 stdbool.h。
- 布尔型数据常用于逻辑判断、函数的返回值、循环控制等场合。
6.常量与变量
- 概念:不可改变的内存称为常量,可以改变的内存称为变量
- 举例:
int a = 100; // a是变量,而100是常量
float f = 3.14; // f是变量,而3.14是常量
char s[] = "abcd"; // s是变量,"abcd"是常量
- 常量的类型
常量举例 | 说明 | 类型 |
100 | 整型 | int |
100L | 长整型 | long |
100LL | 长长整型 | long long |
100ULL | 无符号长长整型 | unsigned long long |
3.14 | 双精度浮点型 | double |
3.14L | 长双精度浮点型 | long double |
‘a’ | 字符型 | char |
“abcd” | 字符指针(字符串\表示该字符串的入口地址) | char * |
7.类型转换
- 概念:不一致但相互兼容的数据类型,在同一表达式中将会发生类型转换。
- 转换模式:
- 隐式(被动的、默认的)转换:系统按照隐式规则(尽量提高精度、不丢失精度)自动进行的转换
- 强制(主动的)转换:用户显式自定义进行的转换
- 隐式规则:从小类型向大类型转换,目的是保证不丢失表达式中数据的精度(从低精度往高精度转换)
- 隐式转换示例代码
char a = 'a';
int b = 12;
float c = 3.14;
float x = a + b - c; // 在该表达式中将发生【隐式转换】,所有操作数被提升为 【float】
- 强制转换:用户强行将某类型的数据转换为另一种类型,此过程可能丢失精度
char a = 'a';
int b = 12;
float c = 3.14;
float x = a + b - (int)c; // 在该表达式中a隐式自动转换为int,c被强制转为int
注意:
在同一表达式中如果出现了无符号整型与有符号整型,那么系统会默认转换为无符号整型,因此对于负数来说被转换为无符号后他的值是非常大的(因为最高位如果为一的话该值必定大于21亿多...)
int Num1 = 123 ;
unsigned Num2 = -1 ;
if (Num1 > Num2)
{
printf("%d>%d\n" , Num1 , Num2);
}
else{
printf("%d>%d\n" , Num2 , Num1);
}
//输出:-1>123.因为在表达式中同时出现了无符号整型和有符号整型,有符号整型默认转换为了有符号整型,
//所以-1的符号位转换为了正值,最高位为1,值达到了21亿多
8.数据类型的本质
- 概念:各种不同的数据类型,本质上是用户与系统对某一块内存数据的解释方式的约定。
- 17620828909
- 推论:
- 类型转换,实际上是对先前定义时候的约定,做了一个临时的打破。
- 理论上,可以对任意的数据做任意的类型转换,但转换之后的数据解释不一定有意义。
9.整型数据尺寸
- 概念:整型数据尺寸是指某种整型数据所占用内存空间的大小
- C语言标准并未规定整型数据的具体大小,只规定了相互之间的 “ 相对大小 ” ,比如:
- short 不可比 int 长
- int 不可以比long 长
- long 不可比 int 短
- long 型数据长度等于系统字长
- 系统字长:CPU 一次处理的数据长度,称为字长。比如32位系统、64位系统。
$ getconf LONG_BIT 64
- 典型尺寸:
- char 占用1个字节
- short 占用2个字节
- int 在16位系统中占用2个字节,在32位和64位系统中一般都占用4个字节
- long 的尺寸等于系统字长
- long long 在32位系统中一般占用8个字节,在64位系统中一般占用8个字节
- 存在问题:
- 同样的代码,放在不同的系统中,可能会由于数据尺寸发生变化而无法正常运行。
- 因此,系统标准整型数据类型,是不可移植的(不具备可移植性),这个问题在底层代码中尤为突出。
10.可移植性整型
- 概念:不管放到什么系统,尺寸保持不变的整型数据,称为可移植性整型
- 关键:typedef
- typedef 关键字是 C 和 C++ 语言中用于定义类型别名的关键字。类型别名可以让程序员更方便地使用现有的类型,而不需要每次都输入完整的类型名称。
类型别名可以用于任何有效的类型,包括基本数据类型、结构体、类、枚举等。类型别名可以用于定义变量、函数参数、函数返回值等。使用类型别名可以提高代码的可读性和可维护性、可移植性,特别是在定义复杂的数据结构时。
typedef int int32_t; // 将类型 int 取个别名,称为 int32_t
typedef long int64_t;// 将类型 long 取个别名,称为 int64_t
- 思路:
-
- 为所有的系统提供一组固定的、能反应数据尺寸的、统一的可移植性整型名称
- 在不同的系统中,为这些可移植性整型提供对应的 typedef 语句
系统中已经有头文件对可移植数据类型进行取别名操作:
/usr/include/x86_64-linux-gnu/bits/types.h
...
...
....
/* Fixed-size types, underlying types depend on word size and compiler. */
typedef signed char __int8_t;
typedef unsigned char __uint8_t;
typedef signed short int __int16_t;
typedef unsigned short int __uint16_t;
typedef signed int __int32_t;
typedef unsigned int __uint32_t;
#if __WORDSIZE == 64 // 条件编译 判断当前__WORDSIZE(系统的位数)
typedef signed long int __int64_t;
typedef unsigned long int __uint64_t;
#else
__extension__ typedef signed long long int __int64_t;
__extension__ typedef unsigned long long int __uint64_t;
#endif
...
....
....
结语:
在这篇博客中,我们深入探讨了C语言中的基本数据类型,包括整型、浮点型、字符型以及它们的修饰符。通过对每种数据类型的特点和应用场景的理解,我们可以更有效地选择合适的数据类型,以优化程序的性能和内存使用。
掌握数据类型对于编写高效、可靠的C语言程序至关重要。同时,了解它们的特性也能帮助我们避免常见的错误,如溢出、精度丢失等,进而提高我们的编程能力。
希望这篇博客能为您的C语言学习之旅提供有价值的指导。数据类型是编程的基石,未来的编程之路请继续深入探索,实践和运用这些知识!
感谢您的阅读,期待在后续的文章中与您分享更多C语言的精彩内容!