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 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也會被改變。如果一個個去查找驗證的話,那麼就需要花費大量的時間。這都是非常不好的習慣。

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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章