C++有两种常量:文字常量和符号常量。这篇我们讲文字常量。
文字常量:
文字常量(常被称为常量)是直接插入到代码中的值。他们是常量因此你不能更改他得值。
return 5; // 5 is an integer literal
bool myNameIsAlex = true; // true is a boolean literal
std::cout << 3.4; // 3.4 is a double literal
就像每个变量都有一个类型一样,常量也会有一个类型,通常是根据它的值来假定的。
Literal value | Examples | Default type |
---|---|---|
integral value | 5, 0, -3 | int |
boolean value | true, false | bool |
floating point value | 3.4, -2.2 | double (not float)! |
char value | ‘a’ | char |
C-style string | “Hello, world!” | const char[14] (see chapter 6) |
文字常量后缀
如果默认的类型不符合你的期望,你可以使用后缀:
Data Type | Suffix | Meaning |
---|---|---|
int | u or U | unsigned int |
int | l or L | long |
int | ul, uL, Ul, UL, lu, lU, Lu, or LU | unsigned long |
int | ll or LL | long long |
int | ull, uLL, Ull, ULL, llu, llU, LLu, or LLU | unsigned long long |
double | f or F | float |
double | l or L | long double |
一般来说对整型没有必要通过后缀来判断,但是也有一些例子:
unsigned int value1 = 5u; // 5 has type unsigned int
long value2 = 6L; // 6 has type long
一般来说浮点数常量默认类型是double,如果想要变成float类型,需要增加f后缀:
float f = 5.0f; // 5.0 has type float
新的程序员往往会困惑,为什么下面的程序并不按照期望的那样显示:
float f = 4.5;
这是因为4.5是没有后缀的,因此是double类型的,而不是float类型。当C++定义常量类型时,他不会关心你用常量做什么。因此你必须将4.5增加后缀,转换成float类型,这样会减小精度值。
C++也支持字符型常量:
std::cout << "Hello, world!" // "Hello, world!" is a C-style string literal
std::cout << "Hello," " world!" // C++ will concatenate sequential string literals
字符型常量在C++中处理起来非常奇怪。目前来说,将该常量作为输出std::out的参数是可以了。但是不能把它当作参数传递给函数。要么不会工作,要么不会想你期望的那样工作。后面我们会讨论C-style的字符串,以及怎么解决这些奇怪的问题。
只要意思明确,字符型常量是可以在C++中正常使用的,这往往会用在初始化一个值,进行数字运算,或者需要打印一个值的时候。
科学记数法的浮点类型
浮点常量的两种类型:
double pi = 3.14159; // 3.14159 is a double literal in standard notation
double avogadro = 6.02e23; // 6.02 x 10^23 is a double literal in scientific notation
当然第二种类型的指数可以是负数:
double electron = 1.6e-19; // charge on an electron is 1.6 x 10^-19
八进制和十六进制常量
在日常的生活中,我们的数字都是由:0,1,2,3,4,5,6,7,8,9组成的,我们叫做十进制数值。在这个系统中我们可以这样:0,1,2,3,4,5,6,7,8,9,10,11,12......通常来说,默认数值是10进制的。
int x = 12; // 12 is assumed to be a decimal number
在2进制中只有0和1,所有的数字都是0和1组成的:0,1,10,01,1010101等
在计算机中还有两种其他的进制类型:8进制和十六进制。
Decimal | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 |
Octal | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 10 | 11 | 12 | 13 |
如果要使用8进制,需要在前面增加一个0:
#include <iostream>
int main()
{
int x = 012; // 0 before the number means this is octal
std::cout << x;
return 0;
}
输出为:10
8进制几乎不使用,建议忽略。下面是16进制的介绍;
Decimal | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 |
Hexadecimal | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | A | B | C | D | E | F | 10 | 11 |
使用16进制需要在前缀增加0x
#include <iostream>
int main()
{
int x = 0xF; // 0x before the number means this is hexadecimal
std::cout << x;
return 0;
}
输出是15
因为在16进制中我们有16个不同的值来表示,正好4bits。通常来说两个16进制的数就可以表示一个byte了。
考虑一个三十二位的整型数值:0011 1010 0111 1111 1001 1000 0010 0110。因为数字的重复和长度,非常难记和读。但是用16进制表示就是:3A7F 9826.这说明16进制在内存中是一种间接的计数方式。因此16进制往往会用来表示地址值和未处理的数据值。
在C++14之前,没有办法直接分配二级制的数据,因此16进制给我们提供了一种的方式:
#include <iostream>
int main()
{
int bin(0);
bin = 0x01; // assign binary 0000 0001 to the variable
bin = 0x02; // assign binary 0000 0010 to the variable
bin = 0x04; // assign binary 0000 0100 to the variable
bin = 0x08; // assign binary 0000 1000 to the variable
bin = 0x10; // assign binary 0001 0000 to the variable
bin = 0x20; // assign binary 0010 0000 to the variable
bin = 0x40; // assign binary 0100 0000 to the variable
bin = 0x80; // assign binary 1000 0000 to the variable
bin = 0xFF; // assign binary 1111 1111 to the variable
bin = 0xB3; // assign binary 1011 0011 to the variable
bin = 0xF770; // assign binary 1111 0111 0111 0000 to the variable
return 0;
}
在C++14之后,可以用0b来表示:
#include <iostream>
int main()
{
int bin(0);
bin = 0b1; // assign binary 0000 0001 to the variable
bin = 0b11; // assign binary 0000 0011 to the variable
bin = 0b1010; // assign binary 0000 1010 to the variable
bin = 0b11110000; // assign binary 1111 0000 to the variable
return 0;
}
因为长整形非常难记,所以可以用'分开:
#include <iostream>
int main()
{
int bin = 0b1011'0010; // assign binary 1011 0010 to the variable
long value = 2'132'673'462; // much easier to read than 2132673462
return 0;
}
幻数,为什么他们不好
考虑如下的小段:
int maxStudents = numClassrooms * 30;
像上面的30被称为幻数,幻数就是在一段代码中直接写死的数字,并且没有任何注释。30是什么意思?及时在这种情况下你可以猜到表示的是一个班级的最大数量,但是始终是不明确的。在更加复杂的情况下,你是没有办法猜到这个数字代表什么意思的,除非有注释。
使用幻数是一种非常差的体验,除了没有备注之外,值的修改也会非常麻烦。假设学校让购买课桌,而现在美分班级最大的认数变成了35,在程序里需要体现出来。考虑下面的情况:
int maxStudents = numClassrooms * 30;
setMax(30);
为了将程序中的size扩展到35,你需要更改。但是setMax中的30和这个30是否是同一个意思?这个setMax中的30需不需要更改?如果都是表示的班级人数,那么就应该一起修改;如果不是,那么需要保留。如果你是通过全部替换修改,那么setMax中的30也会被改变。如果一个个去查找验证的话,那么就需要花费大量的时间。这都是非常不好的习惯。
下一篇文章我们会学习怎么来很好地规避这个问题。