C++ 語言變量 (variable) 初始化 - 賦值 - 聲明 - 定義

Yongqiang Cheng 2021-08-16 01:23:00 阅读数:839

本文一共[544]字,预计阅读时长:1分钟~
c++ variable 初始化 初始

C++ 語言變量 (variable) 初始化 - 賦值 - 聲明 - 定義

變量提供一個具名的、可供程序操作的存儲空間。C++ 中的每個變量都有其數據類型,數據類型决定著變量所占內存空間的大小和布局方式、該空間能存儲的值的範圍,以及變量能參與的運算。對 C++ 程序員來說 變量 (variable)對象 (object) 一般可以互換使用。

1. 變量定義

變量定義的基本形式是:首先是 類型說明符 (type specifier),隨後緊跟由一個或多個變量名組成的列錶,其中變量名以逗號分隔,最後以分號結束。列錶中每個變量名的類型都由類型說明符指定,定義時還可以為一個或多個變量賦初值:

/* yong、value 和 qiang 都是 int。 */
/* yong 和 qiang 的初值為 0。 */
int yong = 0, value, qiang = 0;
/* item 的類型是 Sales。 */
Sales item;
/* string 錶示一個可變長的字符序列。初始化 string 對象,把字面值拷貝給 string 對象。 */
std::string book("yongqiang");

string 在命名空間 std 中定義,string 是一種錶示可變長字符序列的數據類型。

1.1 對象 (object)

通常情况下,對象是指一塊能存儲數據並具有某種類型的內存空間。

1.2 初始值

當對象在創建時獲得了一個特定的值,我們說這個對象被初始化 (initialized) 了。用於初始化變量的值可以是任意複雜的錶達式。因此在同一條定義語句中,可以用先定義的變量值去初始化後定義的其他變量。

/* price 先被初始化為 99.99,隨後被用於初始化 discount。 */
double price = 99.99, discount = price * 0.16;
/* 調用函數 YongQiang,然後用函數的返回值初始化 sale_price。 */
double sale_price = YongQiang(price, discount);

在 C++ 語言中,初始化和賦值是兩個完全不同的操作。初始化不是賦值,初始化的含義是創建變量時賦予其一個初始值,而賦值的含義是把對象的當前值擦除,而以一個新值來替代。

1.3 列錶初始化

C++ 語言定義一個名為 yongqiang 的 int 變量並初始化為 0。

 int yongqiang1 = 0;
int yongqiang2 = { 0 };
int yongqiang3{ 0 };
int yongqiang4(0);

用花括號來初始化變量的形式被稱為列錶初始化 (list initialization)。當用於內置類型的變量時,這種初始化形式有一個重要特點:如果我們使用列錶初始化且初始值存在丟失信息的風險,則編譯器將報錯:

//============================================================================
// Name : Yongqiang Cheng
// Author : Yongqiang Cheng
// Version : Version 1.0.0
// Copyright : Copyright (c) 2020 Yongqiang Cheng
// Description : Hello World in C++, Ansi-style
//============================================================================
#include <iostream>
int main()
{
long double yq = 3.1415926536;
// 錯誤:轉換未執行,存在丟失信息的危險。
int a{ yq }, b = { yq };
//正確:轉換執行,確實丟失信息。
int c(yq), d = yq;
return 0;
}
1>d:\visual_studio_workspace\...\yongqiang.cpp(16): error C2397: conversion from 'long double' to 'int' requires a narrowing conversion
1>d:\visual_studio_workspace\...\yongqiang.cpp(19): warning C4244: 'initializing': conversion from 'long double' to 'int', possible loss of data

使用 long double 的值初始化 int 變量時可能丟失數據,所以編譯器拒絕了 a 和 b 的初始化請求。至少 yq 的小數部分會丟失掉,而且 int 也可能存不下 yq 的整數部分。

1.4 默認初始化

如果定義變量時沒有指定初值,則變量被默認初始化 (default initialized),此時變量被賦予了默認值。

如果是內置類型的變量未被顯式初始化,它的值由定義的比特置决定。定義於任何函數體之外的變量被初始化為 0。定義在函數體內部的內置類型變量將不被初始化 (uninitialized)。一個未被初始化的內置類型變量的值是未定義的,如果試圖拷貝或以其他形式訪問此類值將引發錯誤。

每個類各自决定其初始化對象的方式。是否允許不經初始化就定義對象也由類自己决定。如果類允許這種行為,它將决定對象的初始值到底是什麼。絕大多數類都支持無須顯式初始化而定義對象,這樣的類提供了一個合適的默認值。string 類規定如果沒有指定初值則生成一個空串:

 /* empty 非顯式地初始化為一個空串。 */
std::string empty;
/* 被默認初始化的 Sales 對象。 */
Sales item;

一些類要求每個對象都顯式初始化,此時如果創建了一個該類的對象而未對其做明確的初始化操作,將引發錯誤。

定義於函數體內的內置類型的對象如果沒有初始化,則其值未定義。類的對象如果沒有顯式地初始化,則其值由類確定。

未初始化的變量含有一個不確定的值,使用未初始化變量的值是一種錯誤的編程行為並且很難調試。盡管大多數編譯器都能對一部分使用未初始化變量的行為提出警告,但嚴格來說,編譯器並未被要求檢查此類錯誤。

建議初始化每一個內置類型的變量。雖然並非必須這麼做,但如果我們不能確保初始化後程序安全,那麼這麼做不失為一種簡單可靠的方法。

2. 變量聲明和定義

C++ 語言支持分離式編譯 (separate compilation) 機制,該機制允許將程序分割為若幹個文件,每個文件可被獨立編譯。如果將程序分為多個文件,則需要有在文件間共享代碼的方法。std::cout 和 std::cin,它們定義於標准庫,卻能被我們寫的程序使用。

為了支持分離式編譯,C++ 語言將聲明和定義區分開來。聲明 (declaration) 使得名字為程序所知,一個文件如果想使用別處定義的名字則必須包含對那個名字的聲明。而定義 (definition) 負責創建與名字關聯的實體。變量聲明規定了變量的類型和名字,在這一點上定義與之相同。但是除此之外,定義還申請存儲空間,也可能會為變量賦一個初始值。

如果想聲明一個變量而非定義它,就在變量名前添加關鍵字 extern,而且不要顯式地初始化變量。

 extern int i; // 聲明 i 而非定義 i。
int j; // 聲明並定義 j。

任何包含了顯式初始化的聲明即成為定義。我們能給由 extern 關鍵字標記的變量賦一個初始值,但是這麼做也就抵消了 extern 的作用。extern 語句如果包含初始值就不再是聲明,而變成定義了:

 /* 定義 */
extern double pi = 3.1416;

在函數體內部,如果試圖初始化一個由 extern 關鍵字標記的變量,將引發錯誤。變量能且只能被定義一次,但是可以被多次聲明。

聲明和定義的區別看起來也許微不足道,但實際上卻非常重要。如果要在多個文件中使用同一個變量,就必須將聲明和定義分離。此時,變量的定義必須出現在且只能出現在一個文件中,而其他用到該變量的文件必須對其進行聲明,卻絕對不能重複定義。

2.1 靜態類型

C++ 是一種靜態類型 (statically typed) 語言,其含義是在編譯階段檢查類型。其中,檢查類型的過程稱為類型檢查 (type checking)。對象的類型决定了對象所能參與的運算。在C++語言中,編譯器負責檢查數據類型是否支持要執行的運算,如果試圖執行類型不支持的運算,編譯器將報錯並且不會生成可執行文件。

References

(美) Stanley B. Lippman, (美) Josée Lajoie, (美) Barbara E. Moo 著, 王剛, 楊巨峰 譯. C++ Primer 中文版[M]. 第 5 版. 電子工業出版社, 2013.
https://www.informit.com/store/c-plus-plus-primer-9780321714114

版权声明:本文为[Yongqiang Cheng]所创,转载请带上原文链接,感谢。 https://gsmany.com/2021/08/20210816012233594A.html