《C++ Primer》2.1 基本内置类型

2.1 基本内置类型

C++定义了一套包括算术类型空类型在内的基本数据类型。算术类型包含了字符、整型数、布尔值和浮点数。空类型不对应具体的值

2.1.1 算术类型

这里有个比较有意思的事情,在C++中不建议sizeof(void),而C语言中可以使用sizeof(void),其结果均为1

prog1.cpp:

#include <stdio.h>

int main()
{
    printf("%d\n", sizeof(void));

    return 0;
}

prog1.c:

#include <stdio.h>

int main()
{
    printf("%d\n", sizeof(void));

    return 0;
}

运行结果:

etc@ruc_etc:~/cpp/ch2$ g++ prog1.cpp -o prog1 -Wall -g
prog1.cpp: In function ‘int main()’:
prog1.cpp:5:31: warning: invalid application of ‘sizeof’ to a void type [-Wpointer-arith]
etc@ruc_etc:~/cpp/ch2$ vi prog1.c
etc@ruc_etc:~/cpp/ch2$ cc prog1.c -o prog1_c -Wall -g
etc@ruc_etc:~/cpp/ch2$ ./prog1
1
etc@ruc_etc:~/cpp/ch2$ ./prog1_c
1

数据类型long long是在C++11中新定义的

可寻址的最小内存块称为“字节(byte)”,存储的基本单元称为“字(word)”,它通常由几个字节组成。一个字节要至少能容纳机器基本字符集中的字符。大多数机器的字节由8比特构成,字则由32或64比特构成,也就是4或8字节

也有奇葩的机器模型,比如MIX,一个字节由6bit组成。参见Knuth的《计算机程序设计艺术 第一卷》(TAOCP)第1章 1.3 MIX。

为了赋予内存中某个地址明确的含义,必须首先知道存储在该地址的数据的类型。类型决定了数据所占的比特数以及该如何解释这些比特的内容

与其他整型不同,字符型被分为了三种:char、signed char和unsigned char。类型char和signed char并不一样。尽管字符型有三种,但是字符的表现形式却只有两种:带符号的和无符号的。类型char实际上会表现为上述两种形式中的一种,具体是哪种由编译器决定

在算术表达式中不要使用char或bool,只有在存放字符或布尔值时才使用它们。因为类型char在一些机器上是有符号的,而在另一些机器上又是无符号的,所以如果使用char进行运算特别容易出问题。如果你需要使用一个不大的整数,那么明确指定它的类型是signed char或者unsigned char

执行浮点数运算应选用double。事实上,对于某些机器来说,双精度运算甚至比单精度还快。

练习 2.1

int、long、long long和short的区别是标准定义的最小尺寸不一样,int和short是2字节,long是4字节,long long是8字节。无符号类型只能存储自然数,而有符号类型可以存储负数。float和double都是浮点数类型,但是float的精度要比double低,标准定义的最小尺寸也比double小。

练习 2.2

double。

2.1.2 类型转换

把一个布尔值赋给非布尔类型时,初始值为false则结果为0,初始值为true则结果为1。

把一个浮点数赋给整数类型时,进行了近似处理。结果值将仅保留浮点数中小数点之前的部分。

赋给无符号类型一个超出它表示范围的值时,结果是初始值对无符号类型表示数值总数取模后的余数

例如,8比特大小的unsigned char可以表示0至255区间的值,如果我们赋了一个区间以外的值,则实际的结果是该值对256取模后所得的余数。因此,把-1赋给8比特大小的unsigned char所得的结果是255。

注意,有符号数对有符号数取模的结果是有符号数;有符号数对无符号数取模时,先转换为无符号数再取模,结果是无符号数。

prog2.cpp:

#include <iostream>

using namespace std;

int main()
{
    cout << (-1 % 256) << endl;
    cout << (-1 % 256u) << endl;

    return 0;
}

运行结果:

etc@ruc_etc:~/cpp/ch2$ g++ prog2.cpp -o prog2 -Wall -g
etc@ruc_etc:~/cpp/ch2$ ./prog2 
-1
255

这里需要了解计算机是采用补码的方式存有符号数的。对于一个字节,取值大小是256,对于模256,1和255互为补数,故signed char的-1其二进制形式为0xFF,即255。

赋给带符号类型一个超出它表示范围的值时,结果是未定义的

当一个算术表达式中既有无符号数又有int值时,那个int值就会转换成无符号数

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

编程原则:

避免无法预知和依赖于现实环境的行为(即标准未定义行为)。

切勿混用带符号类型和无符号类型(编译器会报警告)。

练习 2.3
32
4294967264
32
-32
0
0
练习 2.4

2.1.3 字面值常量

以0开头的整数代表八进制数,以0x或0X开头代表十六进制数。默认情况下,十进制字面值是带符号数八进制和十六进制字面值既可能是带符号的也可能是无符号的(标准未定义行为)。

十进制字面值的类型是int、long和long long中尺寸最小的那个,当然前提是这种类型要能容纳下当前的值

八进制和十六进制字面值的类型是能容纳其数值的int、unsigned int、long、unsigned long、long long和unsigned long long中尺寸最小者(标准未定义行为)。

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

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

有点类似于python中序列结构,元素间可由空格、缩进,甚至是换行符分隔,但是不影响它们作为一个整体。这里就不讲究python语法中的缩进原则了。

prog3.cpp:

#include <iostream>

using namespace std;

int main()
{
    cout << "a really, really long string literal "
            "that spans two lines" << endl;

    return 0;
}

运行结果:

etc@ruc_etc:~/cpp/ch2$ g++ prog3.cpp -o prog3 -Wall -g
etc@ruc_etc:~/cpp/ch2$ ./prog3 
a really, really long string literal that spans two lines

C++语言规定的转义序列参考P36。

可以使用泛化的转义序列,其形式是\x后紧跟1个或多个十六进制数字(可以表示多位),或者\后紧跟1-3个八进制数字(也就是说最多表示9位),其中数字部分表示的是字符对应的数值(即标准ASCII码)。

prog4.cpp:

#include <iostream>using namespace std;int main(){    cout << "Hi \x4dO\115!\n";    return 0;}

运行结果:

etc@ruc_etc:~/cpp/ch2$ g++ prog4.cpp -o prog4 -Wall -getc@ruc_etc:~/cpp/ch2$ ./prog4Hi MOM!

其中,M的ASCII码为77。

0x4D = 4 * 16 + 13 = 64 + 13 = 770115 = 64 + 8 + 5 = 77

如果反斜线\后面跟着八进制数字超过3个,只有前3个数字与\构成转义序列。例如,“\1234”表示2个字符,即八进制123对应的字符以及字符4。

\x要用到后面跟着的所有数字。例如,“\x1234”表示一个16位的字符,该字符由这4个十六进制数所对应的比特唯一确定。大多数机器的char型数据占8位,所以上面这个例子可能会报错。所以,超过8位的十六进制字符都是与扩展字符集一起使用的

Unicode包含了各种字母、中日韩文字、emoji等几乎所有语言和领域的符号,它的最低7位与ASCII码是完全兼容的。Unicode只是一个符号集,它只规定了符号的二进制代码,却没有规定这个二进制代码应该如何存储。

UTF-8就是在互联网上使用最广的一种Unicode的实现方式,Unicode与UTF-8也需要转换。

指定字面值的类型的前后缀参见P37。其中前缀修饰字符和字符串字面值,后缀修饰整型和浮点型字面值

nullptr是指针字面值

练习 2.5
(a) ‘a’是字符,类型是char;L‘a’是宽字符,类型是wchar_t;“a”是字符串;L“a”是宽字符型的字符串。(b) 10是int类型;10u是无符号的int类型;10L是long类型;10uL是unsigned long类型;012是八进制字面值,类型不确定;0xC是十六进制字面值,类型不确定。(c) 3.14是浮点数,类型是double;3.14f是浮点数,类型是float;3.14L是浮点数,类型是long double。(d) 10类型为int;10u类型为unsigned int;10.类型为double;10e-2类型为double。
练习 2.6

第二行语句不正确,因为以0开头的是八进制数,不可能出现09,编译会报错。

exercise2_6.cpp:

int main(){    int month = 09, day = 07;    return 0;}

运行结果:

etc@ruc_etc:~/cpp/ch2$ g++ exercise2_6.cpp -o exercise2_6 -Wall -gexercise2_6.cpp:3:17: error: invalid digit "9" in octal constantexercise2_6.cpp: In function ‘int main()’:exercise2_6.cpp:3:9: warning: unused variable ‘month’ [-Wunused-variable]exercise2_6.cpp:3:21: warning: unused variable ‘day’ [-Wunused-variable]
练习 2.7
(a) “Who gose with Fergus?\n”,字符串。(b) 31.4,double。(c) 1024.0,float。(d) 3.14,long double。
练习 2.8
#include <iostream>using namespace std;int main(){    cout << "\x32\115\n";    cout << "\62\t\x4d\n";    return 0;}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值