ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

C 语言数据类型

2022-06-27 08:31:56  阅读:142  来源: 互联网

标签:语言 int 数据类型 unsigned 整数 char long 类型


所谓“类型”,就是相似的数据所拥有的共同特征,知道某个值的数据类型,就能知道该值的特征和操作方式。

基本数据类型有三种:字符(char)、整数(int)和浮点数(float),复杂的类型都是基于它们构建的。

字符类型

字符类型指的是单个字符,类型声明使用char关键字,字符常量必须放在单引号里面。

char c = 'B'; // 声明了变量c是字符类型,并将其赋值为字母B。

字符类型使用一个字节(8位)存储。

C 语言将字符类型当作整数处理,每个字符对应一个整数(由 ASCII 码确定),比如B对应整数66

字符类型在不同系统的默认范围是不一样的。一些系统默认为-128127,另一些系统默认为0255。这两种范围正好都能覆盖0127的 ASCII 字符范围。

只要在字符类型的范围之内(0127),整数与字符是可以互换的,都可以赋值给字符类型的变量。

char c = 66;
// 等同于
char c = 'B';
char a = 'B'; // 等同于 char a = 66;
char b = 'C'; // 等同于 char b = 67;
printf("%d\n", a + b); // 输出 133

转义字符

char t = '\''; // 内部的单引号使用反斜杠转义。

转义写法主要用来表示 ASCII 码定义的一些无法打印的控制字符。

  • \a:警报,这会使得终端发出警报声或出现闪烁,或者两者同时发生。
  • \b:退格键,光标回退一个字符,但不删除字符。
  • \f:换页符,光标移到下一页。在现代系统上,这已经反映不出来了,行为改成类似于\v
  • \n:换行符。
  • \r:回车符,光标移到同一行的开头。
  • \t:制表符,光标移到下一个水平制表位,通常是下一个8的倍数。
  • \v:垂直分隔符,光标移到下一个垂直制表位,通常是下一行的同一列。
  • \0:null 字符,代表没有内容。注意,这个值不等于数字0。

转义写法还能使用八进制和十六进制表示一个字符。

  • \nn:字符的八进制写法,nn为八进制值。
  • \xnn:字符的十六进制写法,nn为十六进制值。
char x = 'B';
char x = 66;
char x = '\102'; // 八进制
char x = '\x42'; // 十六进制

整数类型

基本使用

整数类型用来表示较大的整数,类型声明使用int关键字。

int a;

不同系统的int类型的大小是不一样的,比较常见的是使用4个字节(32位)存储一个int类型的值,但是2个字节(16位)或8个字节(64位)也有可能使用。

  • 16位:-32,768 到 32,767。
  • 32位:-2,147,483,648 到 2,147,483,647。
  • 64位:-9,223,372,036,854,775,808 到 9,223,372,036,854,775,807。

signed,unsigned

  • signed

signed关键字,表示一个类型带有正负号,包含负值。

对于int类型,默认是带有正负号的,也就是说int等同于signed int

  • unsigned

unsigned关键字,表示该类型不带有正负号,只能表示零和正整数。

这样,同样长度的内存能够表示的最大整数值,增大了一倍。比如,16位的signed int最大值为32,767,而unsigned int的最大值增大到了65,535。

unsigned int里面的int可以省略。

unsigned a;

由于字符类型的本质是整数,字符类型char也可以设置signedunsigned

signed char c; // 范围为 -128 到 127
unsigned char c; // 范围为 0 到 255

注意,C 语言规定char类型默认是否带有正负号,由当前系统决定。char不等同于signed char,它有可能是signed char,也有可能是unsigned char

整数的子类型

只需要8位整数时,应该使用char类型。

  • short int(简写为short

占用空间不多于int,一般占用2个字节(整数范围为-32768~32767)。只需要16位整数时,应使用short类型。

  • long int(简写为long

占用空间不少于int,至少为4个字节。需要32位整数时,应使用long类型而不是int类型,可以确保不少于4个字节。

  • long long int(简写为long long

占用空间多于long,至少为8个字节。需要64位的整数时,应该使用long long类型,可以确保不少于8个字节。

short int a;
long int b;
long long int c;

默认情况下,shortlonglong long都是带符号的(signed),即signed关键字省略了。它们也可以声明为不带符号(unsigned),使得能够表示的最大值扩大一倍。

unsigned short int a;
unsigned long int b;
unsigned long long int c;

C 语言允许省略int

short a;
long b;
long long c;

整数的极限值

C 语言的头文件limits.h提供了相应的常量,比如SCHAR_MIN代表 signed char 类型的最小值-128SCHAR_MAX代表 signed char 类型的最大值127

  • SCHAR_MINSCHAR_MAX:signed char 的最小值和最大值。
  • SHRT_MINSHRT_MAX:short 的最小值和最大值。
  • INT_MININT_MAX:int 的最小值和最大值。
  • LONG_MINLONG_MAX:long 的最小值和最大值。
  • LLONG_MINLLONG_MAX:long long 的最小值和最大值。
  • UCHAR_MAX:unsigned char 的最大值。
  • USHRT_MAX:unsigned short 的最大值。
  • UINT_MAX:unsigned int 的最大值。
  • ULONG_MAX:unsigned long 的最大值。
  • ULLONG_MAX:unsigned long long 的最大值。

整数的表示进制

C 语言的整数默认都是十进制数,如果要表示八进制数和十六进制数,必须使用专门的表示法。

八进制使用0作为前缀,比如0170377

int a = 012; // 八进制,相当于十进制的10

十六进制使用0x0X作为前缀,比如0xf0X10

int a = 0x1A2B; // 十六进制,相当于十进制的6699

有些编译器使用0b前缀,表示二进制数,但不是标准。

上述不同的进制只是整数的书写方法,所有整数都是二进制形式存储,跟书写方式无关。

不同进制可以混合使用,比如10 + 015 + 0x20是一个合法的表达式。

printf()的进制相关占位符如下。

  • %d:十进制整数。
  • %o:八进制整数。
  • %x:十六进制整数。
  • %#o:显示前缀0的八进制整数。
  • %#x:显示前缀0x的十六进制整数。
  • %#X:显示前缀0X的十六进制整数。
int x = 100;
printf("dec = %d\n", x); // 100
printf("octal = %o\n", x); // 144
printf("hex = %x\n", x); // 64
printf("octal = %#o\n", x); // 0144
printf("hex = %#x\n", x); // 0x64
printf("hex = %#X\n", x); // 0X64

浮点数类型

浮点数使用 m * b^e 的形式存储数值,m是小数部分,b是基数(通常是2),e是指数部分。

  • float :占用4个字节(32位)

其中8位存放指数 e 的值和符号,剩下24位存放小数 m 的值和符号。

float c = 10.5;
  • double : 占用8个字节(64位)。

  • long double :占用16个字节。

由于存在精度限制,浮点数只是一个近似值,它的计算是不精确的,比如 0.1 + 0.2 并不等于 0.3,而是有一个很小的误差。

布尔类型

C 语言原来并没有为布尔值单独设置一个类型,而是使用整数0表示伪,所有非零值表示真。

int x = 1;
if (x) {
  printf("x is true!\n");
}

C99 标准添加了类型_Bool,表示布尔值。但是,这个类型只是整数类型的别名,还是使用0表示伪,1表示真。

_Bool isNormal;

isNormal = 1;
if (isNormal)
  printf("Everything is OK.\n");

头文件stdbool.h定义了另一个类型别名bool,并且定义了true代表1false代表0

#include <stdbool.h>

bool flag = false;

字面量

字面量(literal)指的是代码里面直接出现的值。

int x = 123; // 123 就是字面量

字面量的类型

编译时,字面量也会写入内存,因此编译器必须为字面量指定数据类型。

  • 整数字面量

一般情况下,十进制整数字面量(比如123)会被编译器指定为int类型。

如果一个数值比较大,超出了int能够表示的范围,编译器会将其指定为long int

如果数值超过了long int,会被指定为unsigned long

如果还不够大,就指定为long longunsigned long long

  • 小数字面量

小数(比如3.14)会被指定为double类型。

字面量后缀

可以为字面量加上后缀,从而为字面量指定数据类型。

int x = 123L; // 字面量123有后缀L,编译器就会将其指定为long类型。

如果希望指定为无符号类型,可以使用后缀uU

字面量后缀可以组合使用。

int x = 123LU;

常用的字面量后缀

  • fFfloat类型。
  • lL:对于整数是long int类型,对于小数是long double类型。
  • llLL:Long Long 类型,比如3LL
  • uU:表示unsigned int,比如15U0377U

数据溢出

每种数据类型都有数值范围,如果存放的数值超出了这个范围(小于最小值或大于最大值),需要更多的二进制位存储,就会发生溢出。大于最大值,叫做向上溢出(overflow);小于最小值,叫做向下溢出(underflow)。

一般来说,编译器不会对溢出报错,会正常执行代码,但是会忽略多出来的二进制位。

unsigned char x = 255;
x = x + 1;

printf("%d\n", x); // 0

为了避免溢出,最好的方法就是将运算结果与类型的极限值进行比较。

但是,不能通过相加的和是否超出了最大值来判断是否发生了溢出。

unsigned int ui;
unsigned int sum;

// 错误
if (sum + ui > UINT_MAX) too_big();
else sum = sum + ui;

// 正确
if (ui > UINT_MAX - sum) too_big();
else sum = sum + ui;

sizeof 运算符

sizeof是 C 语言提供的一个运算符,返回某种数据类型或某个值占用的字节数量。

// 参数为数据类型
int x = sizeof(int);

// 参数为变量
int i;
sizeof(i);

// 参数为数值
sizeof(3.14);

sizeof运算符的返回值,C 语言只规定是无符号整数,并没有规定具体的类型。

不同的系统中,返回值的类型有可能是unsigned int,也有可能是unsigned long,甚至是unsigned long long,对应的printf()占位符分别是%u%lu%llu。这样不利于程序的可移植性。

C 语言提供了一个解决方法,创造了一个类型别名size_t,用来统一表示sizeof的返回值类型。该别名定义在stddef.h头文件(引入stdio.h时会自动引入)里面,对应当前系统的sizeof的返回值类型,可能是unsigned int,也可能是unsigned long

C 语言还提供了一个常量SIZE_MAX,表示size_t可以表示的最大整数。所以,size_t能够表示的整数范围为[0, SIZE_MAX]

printf()有专门的占位符%zd%zu,用来处理size_t类型的值。

printf("%zd\n", sizeof(int));

如果当前系统不支持%zd%zu,可使用%u(unsigned int)或%lu(unsigned long int)代替。

数据类型转换

自动类型转换

  • 赋值运算

赋值运算符会自动将右边的值,转成左边变量的类型。

浮点数赋予整数变量时,C 语言直接丢弃小数部分,而不是四舍五入。

int x = 3.14; // 编译器会自动把3.14先转为int类型,丢弃小数部分,再赋值给x

整数赋值给浮点数变量时,会自动转为浮点数。

float y = 12 * 2; // 变量y的值不是24,而是24.0

字节宽度较小的整数类型,赋值给字节宽度较大的整数变量时,会发生类型提升。

char x = 10;
int i = x + y;

字节宽度较大的类型,赋值给字节宽度较小的变量时,会发生类型降级,自动转为后者的类型。这时可能会发生截值(truncation),系统会自动截去多余的二进制位,导致难以预料的结果。

int i = 321;
char ch = i; // ch 的值是 65 (321 - 256)
  • 混合类型运算

不同类型的值进行混合计算时,必须先转成同一个类型,才能进行计算。

整数与浮点数混合运算时,整数转为浮点数类型,与另一个运算数类型相同。

3 + 1.2; // 4.2

不同的浮点数类型混合运算时,宽度较小的类型转为宽度较大的类型,比如float转为doubledouble转为long double

不同的整数类型混合运算时,宽度较小的类型会提升为宽度较大的类型。比如short转为intint转为long等,有时还会将带符号的类型signed转为无符号unsigned

最好避免无符号整数与有符号整数的混合运算。因为这时 C 语言会自动将signed int转为unsigned int,可能不会得到预期的结果。

int a = -5; 
if (a < sizeof(int))// signed int a 自动转为 unsigned int 4294967291
  do_something(); 
  • 整数类型运算

两个相同类型的整数运算时,或者单个整数的运算,一般来说,运算结果也属于同一类型。但是,宽度小于int的类型,运算结果会自动提升为int

unsigned char a = 66;

if ((-a) < 0) printf("negative\n");
else printf("positive\n");
  • 函数传参
int dostuff(int, unsigned char);

char m = 42;
unsigned short n = 43;
long long int c = dostuff(m, n);

不管参数变量mn原来的类型是什么,都会转成函数dostuff()定义的参数类型。

显式类型转换

原则上,应该避免类型的自动转换,防止出现意料之外的结果。C 语言允许手动转换类型。

只要在值或变量的前面,使用圆括号指定类型(type)即可。

(unsigned char) ch

可移植类型

C 语言的整数类型(short、int、long)在不同计算机上,占用的字节宽度可能是不一样的,无法提前知道它们到底占用多少个字节。

为了代码可以有更好的可移植性,头文件stdint.h创造了一些新的类型别名。

精确宽度类型

精确宽度类型(exact-width integer type),保证某个整数类型的宽度是确定的。

  • int8_t:8位有符号整数。
  • int16_t:16位有符号整数。
  • int32_t:32位有符号整数。
  • int64_t:64位有符号整数。
  • uint8_t:8位无符号整数。
  • uint16_t:16位无符号整数。
  • uint32_t:32位无符号整数。
  • uint64_t:64位无符号整数。

这些都是类型别名,编译器会指定它们指向的底层类型。

比如,某个系统中,如果int类型为32位,int32_t就会指向int;如果long类型为32位,int32_t则会指向long

#include <stdio.h>
#include <stdint.h>

int main(void) {
  int32_t x32 = 45933945; // 变量`x32`声明为`int32_t`类型,可以保证是32位的宽度。
  printf("x32 = %d\n", x32);
  return 0;
}

最小宽度类型

最小宽度类型(minimum width type),保证某个整数类型的最小长度。

  • int_least8_t
  • int_least16_t
  • int_least32_t
  • int_least64_t
  • uint_least8_t
  • uint_least16_t
  • uint_least32_t
  • uint_least64_t

比如,int_least8_t表示可以容纳8位有符号整数的最小宽度的类型。

最快最小宽度类型

最快的最小宽度类型(fast minimum width type),可以使整数计算达到最快的类型。

  • int_fast8_t
  • int_fast16_t
  • int_fast32_t
  • int_fast64_t
  • uint_fast8_t
  • uint_fast16_t
  • uint_fast32_t
  • uint_fast64_t

这些类型在保证字节宽度的同时,追求最快的运算速度。

比如int_fast8_t表示对于8位有符号整数,运算速度最快的类型。这是因为某些机器对于特定宽度的数据,运算速度最快,举例来说,32位计算机对于32位数据的运算速度,会快于16位数据。

可保存指针的整数类型

  • intptr_t:可以存储指针(内存地址)的有符号整数类型。
  • uintptr_t:可以存储指针的无符号整数类型。

最大宽度整数类型

  • intmax_t:可以存储任何有效的有符号整数的类型。
  • uintmax_t:可以存放任何有效的无符号整数的类型。

这两个类型的宽度比long longunsigned long更大。

参考: C 语言教程

标签:语言,int,数据类型,unsigned,整数,char,long,类型
来源: https://www.cnblogs.com/knhap/p/16414991.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有