天天看點

Learning C++ 之 2.8 常量

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 1 2 3 4 5 6 7 8 9 10 11
Octal 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 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
Hexadecimal 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也會被改變。如果一個個去查找驗證的話,那麼就需要花費大量的時間。這都是非常不好的習慣。

下一篇文章我們會學習怎麼來很好地規避這個問題。