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

C++学习(2.1): 基本内置类型

2016-03-29 20:24 267 查看

2.1 基本内置类型

C++ 中定义了一套包括算数类型(arithmetic type) 和空类型(void)在内的基本数据类型。

其中数据类型包含了字符、整型数、 浮点数和布尔值。 空类型不对应具体的值, 仅仅用于一些特定的场合, 例如最常见的是, 当函数不返回任何值得时候, 使用void来作为函数返回值类型。

2.1.1 算数类型

·

算术类型分为两类, 整型(integral type)和浮点型。

算术类型的尺寸(也就是该类型占用的比特数)在不同的机器上有所差别。


列出一些特殊的类型值:

类型含义最小尺寸
boolbool类型未定义
char字符8位
wchar_t宽字符16位
char16_tUnicode字符16位
char32_tUnicode字符32位
long double拓展精度浮点数10位有效数字
1.其中bool类型的取值数是真(true)或者假(false)。

2.C++提供了几种字符类型, 其中多说支持国际化。 基本的字符类型是char, 一个char类型的空间应确保可以存放机器基本字符集中任意字符对应的数字值。 也就是说, 一个char的大小和一个机器直接一样。

其他字符类型用于拓展字符集, 如wchar_t、 char16_t、 char32_t。wchar_t 类型用于确保可以存放机器拓展字符集中的任意一个字符, 类型char16_t和char32_t则为Unicode(自然语言中的字符标准)字符集服务。

除了字符和bool类型之外, 其他整型用于表示(可能)不同尺寸的整数。 c++语言规定一个int至少和一个short一样大, 一个long至少和一个int一样大, 一个long long 至少和一个long一样大。 其中数据类型long long是c++11中新定义的;

计算机中以比特序列存储数据, 每个比特非0即1, 例如:

01101011010111100011001010100111

大多数计算机以2的整数次幂个比特作为块来处理内存, 可寻址的嘴下内存块称之为“字节”, 储存的基本单元称之为“字”, 他通常由几个字节组成。 在c++语言中一个直接至少能容纳及其基本的字符集中的字符。 大多数机器的字节有8比特构成, 字则有32或者64比特构成, 也就是4或者8个字节。

大多数计算机将内存中的每个字节与数字(我们将其称之为地址“address”)关联在一起, 在一个字节为8比特、字为32比特的计算机上 内存如下:

我们能够使用每个地址来表示从这个地址开始的大小不同的bite串。 为了赋予内存中某个地址明确的含义, 必须首先知道存储在这个地址的数据的数据类型。类型决定了这个数据所占用的比特数和以何种方式来解释这些比特数中的内容。

如果00111011这串代码表示的是float类型, 并且该机器中float以32比特存储, 那么我们就知道这个对象的内容占满了整个字。 这个float数的实际值依赖于改机器是如何存储浮点的。 如果这个位置的对象是unsigned char, 并且该机器使用的是 ISO-Latin-1字符集, 那么这个表示的是一个分号。

3.浮点型可以表示单精度、双精度和拓展精度。 C++标准指定了浮点型的有效位数的最小值, 让么人大多数编译器都实现了更高的精度。 通常, float以一个字来表示(4字节 32比特), double以两个字来表示(8字节 64比特), long double以3或4个字来表示(12字节96比特 或者16字节 128比特)。一般来说, 类型float和double分别有7 和16位有效位; 类型long double则常常用来表示有特殊浮点需求的硬件, 特们的具体实现和精度控制各不相同。

·

带符号类型和无符号类型

除去布尔类型和拓展字符型之外, 其他的整型可以划分为带符号(signed)的和无符号(unsigned)两种。 带符号的元素可以表示正数, 负数和0, 无符号只能用来表示大于0的值,

类型int、 short、 long和long long都是带符号的, 通过在这些类型名前添加上unsigned 就可以得到无符号类型, 例如unsigned long。 类型unsigned interesting可以缩写为 unsigned。

与其他整型不同, 字符型被分为了三种: char、 signed char和 unsigned char。

特别需要注意的是, 类型char 和类型unsigned char 并不一样, 尽管字符串有三种, 但是字符的表现形式却只有两种: 带符号的和无符号的。 类型char实际上会表现为上述两种形式中的一种, 具体那种由编译器决定。

无符号类型中所有的bite都用来存储值, 例如, 8比特的unsigned char 可任意表示为0 到255之间的值。

C++标准并没有规定带符号类型该如何表示, 但那时约定了在表示范围内正值和负值应该平衡。 因此8比特的signed char 理论上应该可以表示-127 - +127区间内的值, 大多数现代计算机将自己的表示范围限定在-128至127.

和C语言一样, c++的设计准则就是尽量的接近硬件。 c++的算数类型必须满足各种硬件特质, 所以他们常常显得繁杂而令人不知所措。 事实上, 大多数程序猿能够对数据类型的使用做出限定从而简化选择的过程。 一下是选择的经验和标准。

当明确知晓数值不可能为负值时, 使用无符号类型

使用int执行整数运算。 在实际应用中, short一般显得太小而long一般和int有一样的尺寸。 如果你的数值超出了int的范围, 选用long long

在算数表达式中, 不要使用char 和bool, 只有存放字符或者bool类型是才使用他们。 因为类型char在一些机器上是有符号的, 所以如果使用char进行运算特别容易出问题。 如果你需要使用一个不太大的整数, 那么明确使用类型是signed char 还是unsigned char;

执行浮点运算选用double, 这是因为float 通常精度不够, 而且双精度浮点数和单精度浮点数的计算代价相差无几。 事实上, 对于某些机器上来说, 双精度运算甚至比单精度运算要快。 long double提供的精度在一般情况是没有必要的 , 况且他带来的运行时小号也不容忽视

·

·

·

2.1.2 类型转换

对象的类型定义了对象能包含的数据和能参与的运算, 其中一种运算被大多数类型支持, 就是将对象从一种给定的类型转化成为另一种相关类型

在程序的某处我们使用了一种类型,而其实对象应该选取另一种类型的时候, 程序会自动进行类型转换(convert), 在4.11中我们将进行详细的介绍。 此次有必要说明当给定某种类型的对象赋值给了另一种类型的值的时候会发生什么。

bool b = 42; // b = true;
int i = b; // i = 1
i = 3.14; //  i = 3;
double pi = i; // pi = 3.000000
unsigned char c1 = -1; // char = 255
signed char c2 = 256; // char 未定义


类型所能表示的值的范围决定了转换的过程。


当我们吧一个非bool类型的算术值赋值给bool类型的时, 初始时为0, 那么结果是false, 否则结果为true;

当我们把bool类型的值赋值给非bool类型的时候, 初始值为false时, 结果为0, 初始值为true时, 结果为1。

当我们把一个整数值赋值给浮点类型的时候, 小数部分记为0。 如果该整数所占的空间超过了浮点类型的容量, 精度可能有所损失

我们赋值给无符号类型一个超出他范围的量的时候, 结果是初始值对无符号类型表达式数值总数取模后的余数。 例如, 8比特的小的unsigned char 可以表示0 - 255区间内的值, 如果我们给他赋值了一个区间意外的数, 则实际的结果是该值对256取模之后的余数。 因此把-1 赋值给8比特大小的unsigned char所得到的结果是255(实际上是内存向前溢出, 但只是取最后的32位)

当我们赋给带符号类型一个超出他表示范围的值的时候, 结果是未定义的(undefined)。程序可能继续工作, 可能崩溃, 可能生成垃圾数据。

在程序的某处使用了一种算数类型的值而其实所需要的是另一种类型的值的时候, 编译器同样会执行上述的类型转换。 例如, 如果我们使用了一个非bool值作为条件, 那么它会被自动转化成为bool类型, 这一做法和把非bool值赋值给bool类型变量是的操作完全一致:

如果i的值为0, 那么条件的值为false; 如果i的值为非零, 那么条件的值为true;

·

含有无符号类型的表达式

尽管我们不会故意给无符号对象赋一个赋值, 却能写出这么一个代码。
例如, 当一个不太复杂的算数表达式中既有无符号的int又有int值得时候, 那个int值就会转换成无符号的, 把int转换成无符号的数的过程和吧int直接赋值给无符号的变量一样:


unsigned u = 10;
int i = -42;
printf("%d\n", i + i);
printf("%u\n", u + i);
cout << u + i << endl;
//结果
//-84
//4294967264
//4294967264


在第一个表达式中, 两个整数相加并得到了我们期望的结果。 在第三个表达式中, 相加前把-42转换成了无符号的数。把负数转换成无符号的数类似于直接给无符号的数赋一个负值, 结果等于这个负值加上无符号数的模。

当从无符号的数中减去一个值得时候, 不管这个值是不是无符号数, 我们都必须保证结果不是一个负值。

无符号的数不会小于0, 这一事实同样关系到循环的写法。 例如, 我们倒叙输出10 - 0的过程中可以用以下的循环写出

for(int i = 10; i >= 0; i--)
cout<< i <<" "<<endl;


你可能会觉得反正也不打算输出负数, 可以用无符号数来重写这个循环, 然而这个不经意的改变将会变成死循环


for(unsigned i = 10; i >= 0; i--)
cout<< i <<" "<<endl;


来看看当i等于0的时候会发生什么: 这次迭代输出0之后, 然后继续执行for循环, 表达式i–从i中减去1, 得到的结果是-1, 但是这并不满足unsigned的要求, 此时, i将被取模, 然后转换成一个合法的无符号整形, 所以最终i循环的范围始终是非负数集, 导致死循环。 假设, int占32位, i= 0时, i–的结果是4294967295;

TIP:

如果表达式里基友带符号类型又有无符号类型, 当带符号类型取值为负数的时候会出现异常的结果, 这是因为带符号数会自动的转换成无符号数。 例如, 在一个形如 a*b的式子中, 如果 a = -1, b = 1, 而且a和b都是int, 则表达式的值显然为-1. 然而如果 a是int b 是unsigned, 则结果视电脑上的int数位而定, 在32位的环境中, 结果是4294967295;

2.1.3 字面值常量

形如42的值被称为字面值常量,这样的值一望而知。 每个字面值常量都对应着一种数据类型, 字面值常量的形式决定了他的数据类型。

整型和浮点型字面值

我们可以将字面值写作十进制、八进制、或者十六进制的形式。
以0开头的整数代表八进制整数, 以0x开头的代表十六进制整数。 例如, 我们能用下面的任意一种表示数字为20的整数:


20//十进制。。。。。。。。。024//八进制。。。。。。。。。0x14//十六进制

整型字面值具体的数据类型有它的值和符号决定。 默认情况下, 十进制字符字面值是带符号数, 八进制和十六进制字面值既是带符号的也可能是无符号的。 十进制的字面值类型是 int、long和long long中满足要求的尺寸最小的那一个。 八进制和十六进制字面值的类型是能容纳其数值的int unsigned int、long、unsigned long、long long和unsigned long long 中的能满足要求的尺寸最小者。如果一个字面值连与之关联的最大的数据类型都放不下 那么将发生错误。类型short没有对应的字面值。

尽管字面值可以存储在带符号数据类型之中, 但是严格的来说, 十进制字面值不会是负数。如果我们使用了一个形如 -42 的负十进制字面值, 那个-并不在字面值之内, 他的作用仅仅是对字面值取负值而已。


浮点型字面值表现为一个小数或者以科学计数法表示的指数, 其中指数部分用E或者e标识:

3.14.15926  3.1415926E0      0.       0e0    .0000001


默认的浮点类型的字面值是double

字符和字符串类型的字面值

在单引号括起来的字符成为char类型字面值, 双引号括起来的零个或者多个字符则构成字符串型字面值。 例如, ‘a’是字符字面值 “hello world” 是字符串类型的字面值;

字符串字面值的类型实际上是又常量字符构成的字符数组, 该类型将在后面具体介绍。 编译器在字符串的结尾添加‘\0’, 因此字符串的上都比实际的长度多一。 例如, 字面值‘A’代表的是单独的字符A, 而字符串字面值“A”代表的是一个字符数组, 他是由‘A’和‘\0’两个字符组成的一个数组。

如果两个字符串字面值仅仅是由空格、缩进、换行符分隔开, 则他们实际上是一个整体。 当书写的字符串的字面值比较长, 写在一行不太合适的时候, 就可以采用分开书写的方式

cout << "asadsadsadsadsadsadsa"
"dsadsadsadsadsa" << endl;
//输出 asadsadsadsadsadsadsadsadsadsadsadsa


转义序列

有两类字符程序猿不能直接使用: 一类是不可打印的字符, 如退格或者其他控制符, 因为他们没有可视的图符; 另一类是在c++中有特殊含义的字符(单引号 双引号 问号 反斜线)。 在这些情况下需要用到转义序列, 转义序列均已反斜线开始, c++语言规定的转义序列包括:

含义符号含义符号
换行符\n横向制表符\a
响铃符\t纵向制表符\v
双引号\”退格符\b
反斜线\问号\?
单引号\’回车\n
进纸符\f
我们也可以使用泛化的转义序列, 其后形式\x后面紧跟着1个或者多个十六进制的数字或者\后面紧跟着1个、2个或者3个八进制数字, 其中数字表示的是字符对应的数值。 假设使用的是Latin - 1字符集,下面是一些示例。

\7  响铃   \12  换行   \40   空格       \0   空字符   \115     字符M      \x4d   字符M


注意, 如果反斜线后面跟着超过3个八进制数, 只有前面三个和他构成转义序列。 例如, “\1234”表示八进制数123对应的字符 以及字符4. 相反, \x 要用后面跟着的所有数字, 例如“\x1234”表示一个16位的字符, 该字符由着4个十六进制数所对应的比特唯一确定, 因为计算机的char类型多数是8位, 所以上面这个例子可能会报错。一般来说, 超过八位的十六进制字符都是与下文表中的某个前缀为开头拓展字符集一起使用的。

指定字面值类型

L’A’// 宽字符型字面值, 类型是wchar_t// 这里可以使用l 但是同意与1混淆 所以这里使用大写的L

u8”hi!”//utf-8字符串字面值

42ULL//无符号整形字面值 unsigned long long

1E-3F//单精度浮点型字面值

3.1415926L//拓展精度浮点类型字面值 类型是long double

对于一个整型字面值来说, 我们能分别指定它是否带符号以及占用多少的空间。如果后面后缀中有U, 则该字面值属于无符号类型。 也就是说, 以U为后缀的十进制数、八进制数或者十六进制数 将从 unsigned int、 unsigned long和unsigned long long 中选择一个匹配的空间消耗最小的数据类型。如果后缀有L, 则字面值类型至少是long; 如果后缀是LL, 则字面值的类型将会是long long 和unsigned long long 中的一个. 当然所有的都是可以叠加的如“42ULL”那么他的字面值类型将会是 unsigned long long

bool类型和指针类型的字面值

true 和false 是bool类型的字面值:

bool test = true;


NULL是指针类型的字面值(空指针)

int *ptr = NULL;
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  c++