C++ 笔记(05)— 变量(变量定义、声明、初始化、extern关键字、变量之间转换)
1. 變量定義
變量定義就是告訴編譯器在何處創建變量的存儲,以及如何創建變量的存儲。變量定義指定一個數據類型,并包含了該類型的一個或多個變量的列表,如下所示:
type variable_list;
在這里,type 必須是一個有效的 C++ 數據類型,可以是 char 、 wchar_t 、 int 、 float 、 double 、 bool 或任何用戶自定義的對象,variable_list 可以由一個或多個標識符名稱組成,多個標識符之間用逗號分隔。下面列出幾個有效的聲明:
int i, j, k;
char c, ch;
float f, salary;
double d;
2. 變量初始化
2.1 明確變量類型初始化
變量可以在定義的時候被初始化(指定一個初始值)。初始化器由一個等號,后跟一個常量表達式組成,如下所示:
type variable_name = value;
示例:
extern int d = 3, f = 5; // d 和 f 的聲明
int d = 3, f = 5; // 定義并初始化 d 和 f
byte z = 22; // 定義并初始化 z
char x = 'x'; // 變量 x 的值為 'x'
2.2 使用auto 自動推斷類型
如果將變量的初值設置成了 true ,就可推斷其類型為 bool 。如果您使用的編譯器支持 C++11 和更高版本,可不顯式地指定變量的類型,而使用關鍵字 auto :
auto flag = true
這將指定變量 flag 的類型的任務留給了編譯器。編譯器檢查賦給變量的初值的性質,再確定將變量聲明為什么類型最合適。
#include <iostream>
using namespace std;int main()
{auto flag = true;auto num = 100;cout << "flag sizeof is " << sizeof(flag) << endl; // flag sizeof is 1cout << "num sizeof is " << sizeof(num) << endl; // num sizeof is 4
}
注意:使用 auto 時必須對變量進行初始化,因為編譯器需要根據初始值來確定變量的類型。如果將變量的類型聲明為 auto ,卻不對其進行初始化,將出現編譯錯誤。
2.3 默認初始化
你可能已經注意到了 , 我們通常不對 string 、 vector 等對象進行初始化 。 例如 :
vector<string> v;
string s;
while (cin >> s)
{v.push_back(s);
}
這并不是 “變量必須先初始化再使用 ” 這條規則的例外情況 。 之所以出現這種情況,是因為我們定義 string 類型和 vector 類型時定義了默認初始化機制 , 如果代碼中不顯式進行初始化 ,這兩種對象就會被用一個默認值進行初始化 。 因此 ,上述代碼執行到循環時, v 的值為空 (不包含任何元素), s 的值為空串 "" 。 保證默認初始化的機制稱為默認構造函數。
不幸的是 , C++不允許我們對內置類型設置默認初始化功能 。 全局變量會被默認初始化為 0 , 但你應該盡量少用全局變量 。而最常使用的變量—局部變量和類成員,是不會被初始化的 , 除非你對其進行初始化 (或提供一個默認構造函數 )。
3. 變量聲明
變量聲明向編譯器保證變量以給定的類型和名稱存在,這樣編譯器在不需要知道變量完整細節的情況下也能繼續進一步的編譯。變量聲明只在編譯時有它的意義,在程序連接時編譯器需要實際的變量聲明。
當使用多個文件且只在其中一個文件中定義變量時(定義變量的文件在程序連接時是可用的),變量聲明就顯得非常有用。您可以使用 extern 關鍵字在任何地方聲明一個變量。
雖然您可以在 C++ 程序中多次聲明一個變量,但變量只能在某個文件、函數或代碼塊中被定義一次。
代碼示例:
#include <iostream>using namespace std;// 變量聲明
extern int a, b;
extern int c;
extern float f;int main()
{// 變量定義int a, b;int c;float f;// 初始化a = 10;b = 20;c = a + b;cout << "c is " << c << endl;f = 10/3.0;cout << "f is " << f << endl;return 0;
}
4. 定義與聲明區別
定義包含了聲明,但是聲明不包含定義,如:
int a = 0; //定義并初始化變量 a,同時也就聲明了 a
extern int a; //只是聲明了有一個變量 a 存在,具體 a 在哪定義的,需要編譯器編譯的時候去找。
函數也是類似,定義的時候同時聲明。但如果只是聲明,編譯器只知道有這么個函數,具體函數怎么定義的要編譯器去找。
void fun1(); //函數聲明void fun1(){ //函數定義cout<<"fun1"<<endl;
}
注意:
C/C++ 編譯 cpp 文件是從上往下編譯,所以 main 函數里面調用其他函數時,如果其他函數在 main 函數的下面,則要在 main 函數上面先聲明這個函數?;蛘甙?main 函數放在最下面,這個不僅限于 main 函數,其他函數的調用都是如此。被調用的函數要在調用的函數之前聲明 。
5. extern 關鍵字
extern 關鍵字在變量和函數之前聲明。
5.1 作用在變量之前
變量只允許定義一次,但可以在多個文件中聲明。
test.cpp 中:
int a = 0; // 定義一個變量 a,并賦初值為 0
test1.cpp 中:
extern int a; // 聲明變量 a,它在 test.cpp 中被定義,此處不可賦值
test2.cpp 中:
extern int a; // 聲明變量 a,它在 test.cpp 中被定義,此處不可賦值
5.2 作用在函數之前
test.h:
extern void Fun(); // 函數聲明,extern 用于標識此函數為外部可調用函數
test.cpp:
void Fun(); // 函數定義
5.3 定義函數體內會報錯
示例:
#include <iostream>using namespace std;int main()
{extern int a = 10;cout << "a is " << a << endl;return 0;
}
編譯錯誤信息:
main.cpp: In function ‘int main()’:
main.cpp:7:16: error: ‘a’ has both ‘extern’ and initializerextern int a = 10;
6. 變量之間轉換
變量的類型間是可以互相轉換的,轉換又分為自動轉換和強制轉換。
6.1 自動轉換
- 若參與運算量的類型不同,則先轉換成同一類型,然后進行運算;
- 轉換按數據長度增加的方向進行,以保證精度不降低。如
int型和long型運算時,先把int轉成long型后再進行運算。
a、若兩種類型的字節數不同,轉換成字節數高的類型 ;
b、若兩種類型的字節數相同,且一種有符號,一種無符號,則轉換成無符號類型;
- 所有的浮點運算都是以雙精度進行的,即使僅含
float單精度量運算的表達式,也要先轉換成double型,再作運算; char型和short型參與運算時,必須先轉換成int型;- 在賦值運算中,賦值號兩邊量的數據類型不同時,賦值號右邊量的類型將轉換為左邊量的類型。如果右邊量的數據類型長度比左邊長時,將丟失一部分數據,這樣會降低精度;
#include <iostream>
using namespace std;int main()
{ int a=1;double b=2.5;a=b;cout << "a is " << a << endl; //輸出為 2,丟失小數部分int c = 1;double d = 2.1;cout << "c + d = " << c + d << endl; //輸出為c + d = 3.1return 0;
}
6.2 強制轉換
強制類型轉換是通過類型轉換運算來實現的。其一般形式為:(類型說明符)(表達式)其功能是把表達式的運算結果強制轉換成類型說明符所表示的類型。
#include <iostream>
using namespace std;int main()
{ int a = 1;double b = 2.1;cout << "a + b = " << a + (int)b << endl; //輸出為a + b = 3return 0;
}
6.3 使用列表初始化避免縮窄轉換錯誤
使用取值范圍較大的變量來初始化取值范圍較小的變量時,將面臨出現縮窄轉換錯誤的風險,因為編譯器必須將大得多的值存儲到容量沒那么大的變量中,下面是一個這樣的示例:
int largeNum = 5000000;
short smallNum = largeNum; // compiles OK, yet narrowing error
縮窄轉換并非只能在整型之間進行,但如果使用 double 值來初始化 float 變量、使用 int 值來初始化 float 或 double 變量,或者使用 float 值來初始化 int 變量,可能導致縮窄轉換錯誤。
有些編譯器可能發出警告,但這種警告并不會導致程序無法通過編譯。
為避免這種問題, C++11 引入了列表初始化來禁止縮窄。要使用這種功能,可將用于初始化的變量或值放在大括號( {} )內。列表初始化的語法如下:
int largeNum = 5000000;
short anotherNum{ largeNum }; // error! Amend types
int anotherNum{ largeNum }; // OK!
float someFloat{ largeNum }; // error! An int may be narrowed
float someFloat{ 5000000 }; // OK! 5000000 can be accomodated
這種功能的作用雖然不明顯,但可避免在執行階段對數據進行縮窄轉換導致的 bug,這種 bug 是不合理的初始化導致的,難以發現。
總結
以上是生活随笔為你收集整理的C++ 笔记(05)— 变量(变量定义、声明、初始化、extern关键字、变量之间转换)的全部內容,希望文章能夠幫你解決所遇到的問題。