第一章 命令编译链接文件 make文件
第二章 进入c++
第三章 处理数据
文章目录
- C++变量的命名规则;
- C++内置的整型——unsigned long、long、unsigned int、int、unsigned short、short、char、unsigned char、signed char和bool;
- 如何知道自己计算机类型宽度
- 获得变量的限制
- 表示各种整型的系统限制的climits文件;
- 各种整型的数字字面值(常量);
- 使用const限定符来创建符号常量;
- C++内置的浮点类型——float、double和long double;
- 书写浮点数
- 表示各种浮点类型的系统限制的cfloat文件;
- 各种浮点类型的数字字面值;
- C++的算术运算符;
- 自动类型转换;
- 强制类型转换;
- C++11中的auto声明
- 问答区
- c++ 独特的初始化变量的语法是什么?
- 无符号类型的优势?
- 类型超过自身限制怎么办?
- 我们写程序应该怎么选择类型?,考虑可移植性?
- 编译器是如何知道常量(整型和浮点)的类型呢?
- const为什么比#define好?
c++ 独特的初始化变量的语法是什么?
无符号类型的优势?
类型超过自身限制怎么办?
我们写程序应该怎么选择类型?,考虑可移植性?
编译器是如何知道常量(整型和浮点)的类型呢?
const为什么比#define好?
C++变量的命名规则;
内置的C++类型分两组:基本类型和复合类型。
C++变量的命名规则:
- 在名称中只能使用字母字符、数字和下划线(_)。
- 名称的第一个字符不能是数字。
- 区分大写字符与小写字符。
- 不能将C++关键字用作名称。
- 以两个下划线打头或以下划线和大写字母打头的名称被保留给实现(编译器及其使用的资源)使用。以一个下划线开头的名称被保留给实现,用作全局标识符。
- C++对于名称的长度没有限制,名称中所有的字符都有意义,但有些平台有长度限制。
列子:
int braincount;
braincount = 5;
这些语句告诉程序,它正在存储整数,并使用名称braincount来表示该整数的值(这里为5)。
实际上,程序将找到一块能够存储整数的内存,将该内存单元标记为braincount,并将5复制到该内存单元中;
然后,您可在程序中使用braincount来访问该内存单元。这些语句没有告诉您,这个值将存储在内存的什么位置,但程序确实记录了这种信息。
实际上,可以使用&运算符来检索braincount的内存地址。
C++内置的整型——unsigned long、long、unsigned int、int、unsigned short、short、char、unsigned char、signed char和bool;
有的类型(符号类型)可表示正值和负值,而有的类型(无符号类型)不能表示负值。
术语宽度(width)用于描述存储整数时使用的内存量。
使用的内存越多,则越宽。
C++的基本整型(按宽度递增的顺序排列)分别是char、short、int、long和C++11新增的long long
其中每种类型都有符号版本和无符号版本,因此总共有10种类型可供选择。
整型short、int、long和long long 在不同计算机上的宽度可能是不一样的
满足以下规则:
short至少16位;
int至少与short一样长;
long至少32位,且至少与int一样长;
long long至少64位,且至少与long一样长。
如何知道自己计算机类型宽度
sizeof运算符返回类型或变量的长度,单位为字节
“字节”的含义依赖于实现,因此在一个系统中,两字节的int可能是16位,而在另一个系统中可能是32位。
获得变量的限制
头文件climits(在老式实现中为limits.h)中包含了关于整型限制的信息。具体地说,它定义了表示各种限制的符号名称。
climits文件中包含与下面类似的语句行:
#define INT_MAX 32767
#define和#include一样,也是一个预处理器编译指令。
该编译指令告诉预处理器:在程序中查找INT_MAX,并将所有的INT_MAX都替换为32767。
因此#define编译指令的工作方式与文本编辑器或字处理器中的全局搜索并替换命令相似。
修改后的程序将在完成这些替换后被编译。
使用:
int n_int = INT_MAX; // 传统的C初始化,设置owls为101
int n_intm = INT_MIN; // 可选的c++语法,将wrent设置为432
表示各种整型的系统限制的climits文件;
以下是climits
头文件中的符号常量以及它们的表示:
符号常量 | 表示 |
---|---|
CHAR_BIT | char的位数 |
CHAR_MAX | char的最大值 |
CHAR_MIN | char的最小值 |
SCHAR_MAX | signed char的最大值 |
SCHAR_MIN | signed char的最小值 |
UCHAR_MAX | unsigned char的最大值 |
SHRT_MAX | short的最大值 |
SHRT_MIN | short的最小值 |
USHRT_MAX | unsigned short的最大值 |
INT_MAX | int的最大值 |
INT_MIN | int的最小值 |
UINT_MAX | unsigned int的最大值 |
LONG_MAX | long的最大值 |
LONG_MIN | long的最小值 |
ULONG_MAX | unsigned long的最大值 |
LLONG_MAX | long long的最大值 |
LLONG_MIN | long long的最小值 |
ULLONG_MAX | unsigned long long的最大值 |
各种整型的数字字面值(常量);
整型字面值(常量)是显式地书写的常量,如212或1776。
与C相同,C++能够以三种不同的计数方式来书写整数:
基数为10、基数为8(老式UNIX版本)和基数为16(硬件黑客的最爱)。
C++使用前一(两)位来标识数字常量的基数。
- 第一位为1~9,则基数为10(十进制);因此93是以10为基数的。
- 第一位是0,第二位为1~7,则基数为8(八进制);因此042的基数是8,它相当于十进制数34。
- 前两位为0x或0X,则基数为16(十六进制);因此0x42为十六进制数,相当于十进制数66。
默认情况下,cout以十进制格式显示整数,而不管这些整数在程序中是如何书写的
cout << hex; // 用于改变数字基数的操纵器hex 16; oct 8;
cout<<hex;等代码不会在屏幕上显示任何内容,而只是修改cout显示整数的方式
这些表示方法仅仅是为了表达上的方便。例如,如果CGA视频内存段为十六进制B000,则不必将它转换为十进制数45056再在程序中使用它,而只需使用0xB000即可。但是,不管把值书写为10、012还是0xA,都将以相同的方式存储在计算机中——被存储为二进制数(以2为基数)。
使用const限定符来创建符号常量;
前面关于#define语句的说明,C++有一种更好的处理符号常量的方法
这种方法就是使用const关键字来修改变量声明和初始化。
例如,假设需要一个表示一年中月份数的符号常量,请在程序中输入下面这行代码:
#define Months 12 // 宏定义不用有分号
const int Months = 12; // Months is symbolic constant for 12
常量(如Months)被初始化后,其值就被固定了,编译器将不允许再修改该常量的值。如果您这样做,g++将指出程序试图给一个只读变量赋值。关键字const叫作限定符,因为它限定了声明的含义。
创建常量的通用格式如下:
const type name = value;
注意,**必须在声明中对const进行初始化**。**下面的代码不可以使用是错的**:
const int toes; // value of toes undefined at this point
toes = 10; // too late!
C++内置的浮点类型——float、double和long double;
浮点数能够表示小数值、非常大和非常小的值,它们的内部表示方法与整数有天壤之别。
如果数字很大,无法表示为long类型,如人体的细菌数(估计超过100兆),则可以使用浮点类型来表示。
使用浮点类型可以表示诸如2.5、3.14159和122442.32这样的数字,即带小数部分的数字。计算机将这样的值分成两部分存储。一部分表示值,另一部分用于对值进行放大或缩小。下面打个比方。对于数字34.1245和34124.5,它们除了小数点的位置不同外,其他都是相同的。可以把第一个数表示为0.341245(基准值)和100(缩放因子),而将第二个数表示为0.341245(基准值相同)和10000(缩放因子更大)。缩放因子的作用是移动小数点的位置,术语浮点因此而得名。
书写浮点数
C++有两种书写浮点数的方式。
-
第一种是使用常用的标准小数点表示法:
12.34 // floating-point
939001.32 // floating-point
0.00023 // floating-point
8.0 // still floating-point -
第二种表示浮点值的方法叫作E表示法,其外观是像这样的:3.45E6,这指的是3.45与1000000相乘的结果;E6指的是10的6次方,即1后面6个0。因此,3.45E6表示的是3450000,6被称为指数,3.45被称为尾数。下面是一些例子:
2.52e+8 // can use E or e, + is optional
8.33E-4 // exponent can be negative
7E5 // same as 7.0E+05
-18.32e13 // can have + or - sign in front
1.69e12 // 2010 Brazilian public debt in reais
5.98E24 // mass of earth in kilograms
9.11e-31 // mass of an electron in kilograms
这就是为什么E表示法最适合于非常大和非常小的数
d.dddE+n指的是将小数点向右移n位,而d.dddE-n指的是将小数点向左移n位。之所以称为“浮点”,就是因为小数点可移动。
缺点:浮点运算的速度通常比整数运算慢,且精度将降低
表示各种浮点类型的系统限制的cfloat文件;
各种浮点类型的数字字面值;
C++的算术运算符;
下面是5种基本的C++算术运算符。
- + 运算符对操作数执行加法运算。例如,4+20等于24。
- − 运算符从第一个数中减去第二个数。例如,12−3等于9。
- * 运算符将操作数相乘。例如,28*4等于112。
- / 运算符用第一个数除以第二个数。例如,1000/5等于200。如果两个操作数都是整数,则结果为商的整数部分。例如,17/3等于5,小数部分被丢弃。
- % 运算符求模。也就是说,它生成第一个数除以第二个数后的余数。例如,19%6为1,因为19是6的3倍余1。两个操作数必须都是整型,将该运算符用于浮点数将导致编译错误。
如果其中一个是负数,则结果的符号满足如下规则:(a/b)*b+ a%b = a。
运算符优先级和结合性
算术运算符遵循通常的代数优先级,先乘除,后加减。(乘除用于一个操作数都是从左到右结合的)
自动类型转换;
转换的场景
- 将一种算术类型的值赋给另一种算术类型的变量时,C++将对值进行转换;
- 表达式中包含不同的类型时,C++将对值进行转换;
- 将参数传递给函数时,C++将对值进行转换。
以下是关于潜在的数值转换问题的表格,包括不同类型的转换和可能出现的问题:
转换类型 | 潜在问题 |
---|---|
将较大的浮点类型转换为较小的浮点类型 | - 精度(有效数位)降低 - 值可能超出目标类型的取值范围 - 结果将是不确定的 |
将浮点类型转换为整型 | - 小数部分丢失 - 原始值可能超出目标类型的取值范围 - 结果将是不确定的 |
将较大的整型转换为较小的整型 | - 原始值可能超出目标类型的取值范围 - 通常只复制右边的字节 |
初始化和赋值进行的转换
以{ }方式初始化时进行的转换,称为列表初始化
对类型转换的要求更严格。具体地说,列表初始化不允许缩窄(narrowing)
以确保数据的完整性和类型的一致性
const int code = 66;
int x = 66;
char c1 {31325}; // narrowing, not allowed
char c2 = {66}; // allowed because char can hold 66
char c3 {code}; // ditto
char c4 = {x}; // not allowed, x is not constant
x = 31325;
char c5 = x; // allowed by this form of initialization
表达式中的转换
C++将执行两种自动转换:
首先,一些类型在出现时便会自动转换;
其次,有些类型在与其他类型同时出现在表达式中时将被转换。
整型提升
C++将bool、char、unsigned char、signed char和short值转换为int。具体地说,true被转换为1,false被转换为0。
short chickens = 20; // line 1
short ducks = 35; // line 2
short fowl = chickens + ducks; // line 3
为执行第3行语句,C++程序取得chickens和ducks的值,并将它们转换为int。
然后,程序将结果转换为short类型,因为结果将被赋给一个short变量。
这种说法可能有点拗口,但是情况确实如此。前面说过通常将int类型选择为计算机最自然的类型,这意味着计算机使用这种类型时,运算速度可能最快。
下面也整型提升
如果short比int短,则unsigned short类型将被转换为int;
如果两种类型的长度相同,则unsigned short类型将被转换为unsigned int。这种规则确保了在对unsigned short进行提升时不会损失数据。
将不同类型进行算术运算时,也会进行一些转换,例如将int和float相加时。当运算涉及两种类型时,较小的类型将被转换为较大的类型。
强制类型转换;
C++还允许通过强制类型转换机制显式地进行类型转换(C++认识到,必须有类型规则,而有时又需要推翻这些规则)
强制类型转换的格式有两种
(long) thorn // returns a type long conversion of thorn
long (thorn) // returns a type long conversion of thorn
强制类型转换不会修改thorn变量本身,而是创建一个新的、指定类型的值,可以在表达式中使用这个值。
(typeName) value // converts value to typeName type
typeName (value) // converts value to typeName type
第一种格式来自C语言,第二种格式是纯粹的C++。
C++11中的auto声明
在初始化声明中,如果使用关键字auto,而不指定变量的类型,编译器将把变量的类型设置成与初始值相同:
auto n = 100; // n is int
auto x = 1.5; // x is double
auto y = 1.3e12L; // y is long double
自动推断类型并非为这种简单情况而设计的;
事实上,如果将其用于这种简单情形,甚至可能让您误入歧途
假设要将x、y和z都指定为double类型,并编写了如下代码:
auto x = 0.0; // ok, x is double because 0.0 is double
double y = 0; // ok, 0 automatically converted to 0.0
auto z = 0; // oops, z is int because 0 is int
显式地声明类型时,将变量初始化0(而不是0.0)不会导致任何问题,但采用自动类型推断时,这却会导致问题。
处理复杂类型,如标准模块库(STL)中的类型时,自动类型推断的优势才能显现出来。例如,对于下述C++98代码:
std::vector<double> scores;
std::vector<double>::iterator pv = scores.begin();
C++11允许您将其重写为下面这样:
std::vector<double> scores;
auto pv = scores.begin();
问答区
c++ 独特的初始化变量的语法是什么?
int owls = 101; // 传统的C初始化,设置owls为101
int wrens(432); // 可选的c++语法,将wrent设置为432
还有另一种初始化方式,采用这种方式时,可以使用等号(=),也可以不使用
大括号初始化器,这种方式用于数组和结构,但在C++98中,也可用于单值变量:
int emus{7}; // set emus to 7
int rheas = {12}; // set rheas to 12
大括号内可以不包含任何东西。在这种情况下,变量将被初始化为零:
int rocs = {}; // set rocs to 0
int psychics{}; // set psychics to 0
通过使用C++新增的大括号初始化器,初始化常规变量的方式与初始化类变量的方式更像。C++11使得可将大括号初始化器用于任何类型(可以使用等号,也可以不使用),这是一种通用的初始化语法。
无符号类型的优势?
无符号变体,其优点是可以增大变量能够存储的最大值。
简单来是就是将存符号的那一位来放数了,不就能增大变量能够存储的最大值
类型超过自身限制怎么办?
如果超越了限制,其值将为范围另一端的取值下图。C++确保了无符号类型的这种行为;
但C++并不保证符号整型超越限制(上溢和下溢)时不出错,而这正是当前实现中最为常见的行为。
这个图很好记,只要注意一点,无论是有符号数还是无符号数
他们都像是最小的和最大的数为线头,然后围起来的一个圈。
我们写程序应该怎么选择类型?,考虑可移植性?
int被设置为对目标计算机而言最为“自然”的长度。
自然长度(natural size)指的是计算机处理起来效率最高的长度。如果没有非常有说服力的理由来选择其他类型,则应使用int。
看看可能使用其他类型的原因
- 如果变量表示的值不可能为负,如文档中的字数,则可以使用无符号类型,这样变量可以表示更大的值。
- 如果知道变量可能表示的整数值大于16位整数的最大可能值,则使用long。即使系统上int为32位,也应这样做。这样,将程序移植到16位系统时,如果要存储的值超过20亿,可使用long long。为提高可移植性,请使用long
- 如果只需要一个字节,可使用char
编译器是如何知道常量(整型和浮点)的类型呢?
整型
cout << "Year = " << 1492 << "\n";
程序将把1492存储为int、long还是其他整型呢?
答案:
除非有理由存储为其他类型(如使用了特殊的后缀来表示特定的类型,或者值太大,不能存储为int),否则C++将整型常量存储为int类型。
后缀:
后缀是放在数字常量后面的字母,用于表示类型。
整数后面的l或L后缀表示该整数为 long 常量
u 或 U 后缀表示unsigned int常量
组合:
ul(可以采用任何一种顺序,大写小写均可)表示unsigned long常量(由于小写l看上去像数字1,因此应使用大写L作后缀)。例如,在int为16位、long为32位的系统上,数字22022被存储为int,占16位,数字22022L被存储为long,占32位。同样,22022LU和22022UL都被存储为unsigned long。C++11提供了用于表示类型long long的后缀ll和LL,还提供了用于表示类型unsigned long long的后缀ull、Ull、uLL和ULL。
浮点
常量的时候,程序将把它存储为哪种浮点类型呢?
在默认情况下,像8.24和2.4E8这样的浮点常量都属于double类型。
如果希望常量为float类型,请使用f或F后缀。对于long double类型,可使用l或L后缀(由于l看起来像数字1,因此L是更好的选择)。下面是一些示例:
1.234f // a float constant
2.45E20F // a float constant
2.345324E28 // a double constant
2.2L // a long double constant
const为什么比#define好?
const比#define好。首先,它能够明确指定类型。
其次,可以使用C++的作用域规则将定义限制在特定的函数或文件中
(作用域规则描述了名称在各种模块中的可知程度,将在第9章讨论)。
可以将const用于更复杂的类型,如第4章将介绍的数组和结构。