C语言学习笔记:基本数据类型

1 min read

整型 int

C语言的整型表示的是整数,分为有符号(int)和无符号(unsigned int)。其中无符号整型只能表示非负整数(自然数),不管是有符号还是没符号都存在极限值(表示的数字不能超过或小于某个值),而在C语言中,极限值并不是固定的,不同硬件、操作系统、编译器都可能有不同的值。想要了解当前C语言环境的整型极限值,可以通过引入limits.h头文件查看。具体代码:

注意,打印UINT_MAX时不能够使用%d,否则会输出-1,同样打印ULONG_MAX时,无法使用%ld,否则同样会输出-1。上述代码在我的电脑上编译执行后,输出的内容为:

这些值是在limits.h头文件中通过 #define 指令来定义的。具体含义如下:

描述
CHAR_BIT 定义一个字节的比特数。
SCHAR_MIN 定义一个有符号字符的最小值。
SCHAR_MAX 定义一个有符号字符的最大值。
UCHAR_MAX 定义一个无符号字符的最大值。
CHAR_MIN 定义类型 char 的最小值,如果 char 表示负值,则它的值等于 SCHAR_MIN,否则等于 0。
CHAR_MAX 定义类型 char 的最大值,如果 char 表示负值,则它的值等于 SCHAR_MAX,否则等于 UCHAR_MAX。
MB_LEN_MAX 定义多字节字符中的最大字节数。
SHRT_MIN 定义一个短整型的最小值。
SHRT_MAX 定义一个短整型的最大值。
USHRT_MAX 定义一个无符号短整型的最大值。
INT_MIN 定义一个整型的最小值。
INT_MAX 定义一个整型的最大值。
UINT_MAX 定义一个无符号整型的最大值。
LONG_MIN 定义一个长整型的最小值。
LONG_MAX 定义一个长整型的最大值。
ULONG_MAX 定义一个无符号长整型的最大值。

字符型本质上是int型,C语言把字符型当作小整数进行处理,我们常见的ASCII码表即为字符与int值之间的映射关系。例如字符’a’对应的值为97,字符’A’对应的值为65,字符’0’的值为48。在ASCII码中字符的取值范围为00000000~11111111,可以看成是0-127的整数。虽然ASCII码的取值范围是0-127,但是C语言中字符型char的表示范围和整型int一样受环境影响,具体可看上述示例。

备注:C语言中 getchar()函数返回的类型为int型而非char类型

原因:

  • getchar()除获得一般字符外,还会获得输入结束符EOF
  • EOF在stdio.h中被定义为-1
  • 部分编译器定义的char类型的范围为0-255

枚举类型 enum

枚举类型enum本质和字符类型一样,也可理解为映射表,只不过该映射关系需要自行定义。大致的使用方式如下:

其中:

  • 映射的数值可以自行指定
  • 首位如果缺省,则数字从0开始
  • 中间位缺省,则数字为前一位+1

浮点类型 float和double

浮点类型(浮点数)指的就是小数,float(单精度浮点)和double(双精度浮点)的区别是double的精度更高,在大部分环境中,double的有效数字为16位,float的有效数字为7位。相应的double消耗的内存是float的两倍,运行速度也比float慢的多。

C语言标准规定,浮点数在内存中以科学计数法的形式来存储,具体形式为:

对各个部分的说明:

  • flt 是要表示的浮点数。
  • sign 用来表示 flt 的正负号,它的取值只能是 0 或 1:取值为 0 表示 flt 是正数,取值为 1 表示 flt 是负数。
  • base 是基数,或者说进制,它的取值大于等于 2(例如,2 表示二进制、10 表示十进制、16 表示十六进制……)。数学中常见的科学计数法是基于十进制的,例如 6.93 × 1013;计算机中的科学计数法可以基于其它进制,例如 1.001 × 27 就是基于二进制的,它等价于 1001 0000。
  • mantissa 为尾数,或者说精度,是 base 进制的小数,并且 1 ≤ mantissa < base,这意味着,小数点前面只能有一位数字;
  • exponent 为指数,是一个整数,可正可负,并且为了直观一般采用十进制表示。

浮点类型与整型一样,能够表示的范围受当前环境影响。想要了解具体的极限值信息,可以从flaot.h中查看。float.h 头文件对 float、double 和 long double 三种类型的浮点数进行了说明,并且宏的命名也非常规范,以FLT_开头的表示宏用来描述 float 类型的特性,以DBL_开头的表示宏用来描述 double 类型的特性,以LDBL_开头的表示宏用来描述 long double 类型的特性。查看方式:

在我电脑上返回的值如下:

具体含义:

描述
FLT_EVAL_METHOD FLT_EVAL_METHOD 用来指明在表达式求值(尤其是数学运算)过程中是否需要提升浮点数的类型,可能的取值有:

l -1:未知的,不确定的。

l 0:不提升类型,使用当前的类型。

l 1:将浮点数提升到 double 类型,大于等于 double 类型的保持不变;也就是说,将 float 类型提升为 double 类型,double 和 long double 类型不变。

l 2:将浮点数提升到 long double;也就是说,将 float、double 提升到 long double 类型,long double 类型保持不变。

FLT_EVAL_METHOD 对所有浮点数类型(float、double 和 long double)都有效,也就是说,所有浮点数类型都必须采用相同的类型提升。提升类型能够提高浮点数的精度,让表达式的结果更加精确。

 

FLT_ROUNDS 浮点数的舍入模式,可能的取值有:

l -1:未知的,不确定的;

l 0:向零舍入,也就是直接截断;

l 1:舍入到最接近的值,类似于“四舍五入”,但不完全相同;

l 2:向 +∞ 方向舍入(向上舍入);

l 3:向 -∞ 方向舍入(向下舍入)。

FLT_ROUNDS 对所有浮点数类型(float、double 和 long double)都有效,也就是说,所有浮点数类型都必须采用相同的舍入模式。

FLT_RADIX 表示基数或者进制,也即上面公式中 base 的值。

FLT_RADIX 对所有浮点数类型(float、double 和 long double)都有效,也就是说,所有浮点数类型都必须采用相同的种基数(进制)。

 

FLT_MANT_DIG

DBL_MANT_DIG

LDBL_MANT_DIG

基数(进制)为 FLT_RADIX 时,尾数 mantissa 的最大长度(最大位数),也可以说是浮点数的精度。注意,这里所说的长度包含了整数部分和小数部分。

 

DECIMAL_DIG

 

在不损失精度精度的情况下,能够将 long double 转换成至少 DECIMAL_DIG 个十进制数字;反过来,也能将至少 DECIMAL_DIG 个十进制数字转换成 long double。也就是说,DECIMAL_DIG 是用于 long double 序列化和反序列化时的十进制精度。
FLT_DIG

DBL_DIG

LDBL_DIG

转换成十进制形式后,小数点后精确数字(能够保证精度的数字)的位数。
FLT_MIN_EXP

DBL_MIN_EXP

LDBL_MIN_EXP

基数(进制)为 FLT_RADIX 时,规格化浮点数的指数(也即 exponent)的最小值(为负数)。

 

FLT_MAX_EXP

DBL_MAX_EXP

LDBL_MAX_EXP

基数(进制)为 FLT_RADIX 时,规格化浮点数的指数(也即 exponent)的最大值(为正数)。

 

FLT_MIN_10_EXP

DBL_MIN_10_EXP

LDBL_MIN_10_EXP

转换成十进制形式后,规格化浮点数的指数的最小值(为负数)。

 

FLT_MAX_10_EXP

DBL_MAX_10_EXP

LDBL_MAX_10_EXP

转换成十进制形式后,规格化浮点数的指数的最大值(为正数)。

 

FLT_MIN

DBL_MIN

LDBL_MIN

最小的有效浮点数的值(为负数),也即浮点数的最小值。

 

FLT_MAX

DBL_MAX

LDBL_MAX

最大的有效浮点数的值(为正数),也即浮点数的最大值。

 

FLT_EPSILON

DBL_EPSILON

LDBL_EPSILON

1 和大于 1 的最小浮点数之间的差值(可表示的最小有效数字)。

 

FLT_TRUE_MIN

DBL_TRUE_MIN

LDBL_TRUE_MIN

分别为 float、double 与 long double 的最小正数值

 

FLT_DECIMAL_DIG

DBL_DECIMAL_DIG

LDBL_DECIMAL_DIG

从 float/double/long double 转换到至少有 FLT_DECIMAL_DIG/DBL_DECIMAL_DIG/LDBL_DECIMAL_DIG 位数字的十进制,再转换回原类型为恒等转换:这是序列化/反序列化浮点值所要求的十进制精度。分别定义为至少 6、10 和 10,对于 IEEE float 为 9,对于 IEEE double 为 17。
FLT_HAS_SUBNORM

DBL_HAS_SUBNORM

LDBL_HAS_SUBNORM

指明类型是否支持非正规数值:-1 为不确定,0 为不支持,1 为支持。

类型转换

算术转换

所谓算数转化就是将运算(比较)前将2个操作数的类型转化为相同类型,其中表示空间较小的会自动转化为表示空间较大的。比如计算1+2.0,会将1转换为1.0,再与2相加。相关的优先级为:

其中容易遇到的坑为,当有符号的遇到无符号的时候会将去转化为无符号,如果有符号的数字为负数就会产生问题。

上述代码编译执行后输出的结果为:

导致x从-1到4294967295的原因是,在负数从有符号转到无符号的过程中会自动加上4294967295(最到的无符号整数)+1。

赋值转换

赋值转换指的是在进行赋值操作时,赋值运算符右边的数据类型必须转换成赋值号左边的类型,若右边的数据类型的长度大于左边,则要进行截断。比如将浮点数赋值给整型变量就会直接丢失小数部分。

输出转换

输出转化是指在格式化输出(printf)的时候,会将类型转化为制定的格式,比如%d代表的就是int型。

对于ANSI C以前的C,比int小的类型会被转化成int,float会被转化成double,所以不会出现接受float类型参数的函数,针对char和short,编译器通过别的方式做了补救措施。因为ANSI C有原型声明,所以无论是char还是float,都可以直接传递。可是,对于printf()这样具有可变参数的函数,原型声明对可变长部分的参数是不产生任何影响的。因此,这部分的参数同样会被编译器进行类型转换操作。也就是说,比int小的会被转换成int,float会被转化成double。结果就是不能向printf传递char或float参数。所以:

  • float、double共用了%f,如果你使用%lf反而会提出警告。
  • char、short、int共用了%d

但是,在scanf中如果想要使用double,就必须使用%lf。 

强制转换

强制转化非常的简单,就是在变量或表达式前加上“(类型名)”,如果类型的标识的标示范围<原值,会发生截断问题。常用的强制转化比如在计算两个整数相除。int_x / int_y默认返回的是被截断的整数,如果想让除法结果返回小数,只要在人员一个变量面前添加(float)即可。比如(float) int_x / int_y,注意,这里的强制转换要比算法运算符高,所以这里会先进行强制转换后进行算数转换。

打赏作者
微信支付标点符 wechat qrcode
支付宝标点符 alipay qrcode

含C/C++代码包Anaconda安装问题

上篇文章主要讲了libffm在Windows系统下安装遇到的问题,今天在Linux环境下的Anaconda中安
1 min read

FFM/libffm在Windows上的使用

FFM 的作者Yu-Chin Juan在GitHub上开源了C++版本的代码libffm,由于日常的数据处理都
5 min read

使用Python获取照片Exif信息

什么是Exif? Exif(Exchangeable image file format)是专门为数码相机的照
4 min read

发表评论

电子邮件地址不会被公开。 必填项已用*标注