日本免费高清视频-国产福利视频导航-黄色在线播放国产-天天操天天操天天操天天操|www.shdianci.com

學無先后,達者為師

網(wǎng)站首頁 編程語言 正文

C++?中的類型詳細_C 語言

作者:一個熱愛學習的深度渣渣 ? 更新時間: 2021-12-08 編程語言

前言:

?類型一直是C++中最重要的部分,相比于其他高級語言,C++的類型會復雜許多,往往一個類型匹配錯誤就會導致程序報錯,本篇主要講解一些常用類型的概念以及細節(jié),如果對于C++有一定基礎的,可以跳轉到思考部分,從中了解自己的掌握程度;

一、初始化與賦值

定義:初始化與賦值語句是程序中最基本的語句,功能是將某個值與一個對象關聯(lián)起來;

  • 值:字面量、對象(變量或常量)所表示的值等
  • 標識符(對象):變量、常量、引用

初始化的基本操作:

  • 1、在內(nèi)存中開辟空間、保存相應的數(shù)值;
  • 2、在編譯器中構造符號表、將標識符與相關內(nèi)存空間關聯(lián)起來;

二、 類型概述

下面通過幾點概要說明:

1、類型是編譯期概念,可執(zhí)行程序中不存在類型的概念;

2、C++是強類型語言;

強類型語言定義: 一旦一個變量被定義類型,如果不經(jīng)過強制轉換,那么它永遠就是該數(shù)據(jù)類型;

弱類型語言定義: 某一變量被定義類型,該變量可根據(jù)環(huán)境變化自動進行轉換,不需要強轉;

3、引入類型是為了更好描述程序,防止誤用;

4、類型描述的信息:

存儲所需要的大小: (sizeof,標準沒有嚴格限制,根據(jù)硬件不同字節(jié)數(shù)也不同)
取值空間: (可用std::numeric_limits來判斷,超過范圍可能產(chǎn)生溢出)

#include<iostream>
#include<limits>

int main() {
    int x = 10;

    std::cout << std::numeric_limits<int>::min() << std::endl;    //-2147483648
    std::cout << std::numeric_limits<int>::max() << std::endl;    //2147483647

    std::cout << std::numeric_limits<unsigned int>::min() << std::endl;  //0
    std::cout << std::numeric_limits<unsigned int>::max() << std::endl;  //4294967295
}

由上面程序運行結果可知,無符號int類型占4個字節(jié),也就是32個比特位,所以最大范圍為232,在不同的硬件下可能不同;

  • 對齊信息(一般存放在內(nèi)存中按類型的對齊信息的整數(shù)倍存儲,比如int的對齊信息為4個字節(jié),那存儲的空間首地址為4的倍數(shù),在結構體中,因為存在對齊信息,char也會按4個字節(jié)保存)
  • 類型可執(zhí)行的操作

三、類型分類

類型可以劃分為基本類型和復雜類型;

基本(內(nèi)建)類型:C++語言中支持的類型,包含以下幾種:

1、數(shù)值類型

字符類型:charwchar_tchar16_tchar32_t,通常為1個字節(jié),表示256個值,也就是ASCII編碼的字符;
整數(shù)類型:帶符號整數(shù)類型(shortintlonglong long),無符號整數(shù)類型(unsigned+帶符號整數(shù)類型)
浮點類型:floatdoublelong double

注意:在C++11中引入了固定尺寸的整數(shù)類型,如int32_t等,之前在針對開發(fā)板的程序中有見過該類型,主要是便于硬件的可移植性:

2、void類型

復雜類型:由基本類型組合、變種所產(chǎn)生的類型,可能是標準庫引入,或自定義類型;

四、字面值及其類型

字面值:在程序中直接表示為一個具體數(shù)值或字符串的值;

每個字面值都有其類型,例子如下:

  • 整數(shù)字面值(int):20(十進制)、024(八進制)、0x14(十六進制)
  • 浮點數(shù)(double):1.3、1e8
  • 字符字面值(char): ‘c'、'\n'
  • 字符串字面值(char[4]): “cpp”,注意這里字符串后會默認加/0,所以是四個字符長度
  • 布爾字面值(bool): True、False

像如果想要定義float類型的數(shù),可以加入后綴如1.3f

C++提供了用戶創(chuàng)建自定義后綴的函數(shù):

#include<iostream>

// 后綴可自行定義,我這里用_bang
int operator "" _bang(long double x)
{
    return (int)x * 2;
}

int main() {
    int x = 7.14_bang;
    std::cout << x << std::endl;
}

上面代碼將7.14的浮點類型轉換成整型并增大一倍,可自行定義后綴試一下;

五、變量及其類型

變量:對應一段存儲空間,可以改變其中內(nèi)容;

聲明與定義的區(qū)別:不能重定義已經(jīng)初始化的變量,需要加入extern用來聲明;

初始化:全局變量會默認初始化為0,局部變量會缺省初始化(隨機數(shù)值);

六、復合類型

1、指針:一種間接類型;

在這里插入圖片描述

如上圖為一個指針p指向一段內(nèi)存,p保存的為val的地址,我們通過打印尺寸可知,指針p為8個字節(jié);

特點:

  • 可以"指向"不同的對象;
  • 具有相同的尺寸;
  • 指針與bool的隱式轉換:非空指針可以轉換為true、空指針可以轉換為false

注意:兩個符號:*(解引用符)、&(取地址符);

解引用符在不同環(huán)境下含義不同,看如下代碼:

int x = 10;
int* p = &x;  // 表示p為一個int指針類型
*p;       // 表示解引用,獲取指針指向地址的值

關于nullptr:

  • 一個特殊的對象(類型為nullptr_t),表示空指針;
  • 類似于C中的NULL,但更加安全;

void 指針*:沒有記錄對象的尺寸,可以表示任意類型指針,一般作為形參或返回值;

指針對比對象:指針復制成本低,引用成本高;

總結:指針在程序中的作用,最重要的就是作為參數(shù)傳入,由于數(shù)據(jù)類型可能很大,傳入指針大小固定為8個字節(jié),并且指針值為地址可復制,復制成本低,并且可在函數(shù)中改變變量的值;

2、引用

取地址符&也有兩個含義:

int x = 10;
&x;      // 取地址符
int& ret = x;    // 定義ret為一個引用類型

特點:

  • 是對象的別名,不能綁定字面值(指針也不能指向字面值);
  • 構造時綁定對象,在其生命周期內(nèi)不能綁定其他對象(賦值操作會改變對象內(nèi)容);
  • 不存在空引用,但可能存在非法引用,總體比指針安全;
  • 屬于編譯期概念,在底層還是通過指針實現(xiàn);

七、常量類型

  • 使用關鍵字const聲明常量對象;
  • 是編譯期概念,由編譯器保證,作用為防止非法操作、優(yōu)化程序邏輯;

常量指針(頂層常量):

int* const p = &x;

常量指針表示指針為常量,指針不能更改指向;

底層常量:

const int* p = &x;

底層常量表示指針指向的地址的內(nèi)容不能發(fā)生改變,指針指向可改變;

常量引用:

const int&定義一個常量引用;
主要用于函數(shù)形參(對于較復雜的數(shù)據(jù)類型);
可以綁定字面值;

常量表達式:

constexpr int x = 1;  // x的類型仍為const int

聲明的是編譯期的常量,編譯器可以對其進行優(yōu)化;

八、類型別名

類型別名:引入特殊的含義或便于使用,例如size_t

引入類型別名的兩種方式:

1、typedef int Mytype;

2、using Mytype = int;(C++11后)

第二種方式更好;

  • 應將指針類型別名視為一個整體,引入常量const表示指針為常量的類型;
  • 不能通過類型別名構造引用的引用;

九、類型自動推導

定義:通過初始化表達式定義對象類型,編譯器會自動推導得到;(C++11開始)

推導得到的類型還是強類型,并不是弱類型;

自動推導的幾種形式:

1、auto:最常用的形式,會產(chǎn)生類型退化(由于左值右值的類型區(qū)別);

2、const autoconstexpr auto:推導出的是常量、常量表達式類型;

3、auto&:推導出引用類型,避免類型退化;

4、decltype(exp) :返回exp表達式的類型(左值加引用);

5、decltype(val) :返回val的類型;

6、decltype(auto) :簡化decltype的使用,C++14開始支持;

補充:類型退化表示一個變量作為左值和右值時類型不同,例如數(shù)組作為右值為指針;

十、域與對象聲明周期

域(scope):表示程序中的一部分,其中的名稱有唯一含義,有全局域、塊域等;

域可以嵌套,嵌套域中定義的名稱可以隱藏外部域中定義的名稱;
對象的生命周期起始于被初始的時刻,終止于被銷毀的時刻;
全局對象的生命周期是整個程序運行期間,局部對象終止在所在域執(zhí)行完成;
思考

1、思考下下面關于指針的兩行代碼的含義

int x = 1;
int* p = &x;
int y = 0;
*p = y;    // 第一行
p = &y;    // 第二行

這兩行表明了指針的一個特定,可改變性,每一行的含義如下:

第一行:將指針p指向的內(nèi)存地址的值改變?yōu)閥;

第二行:不改變x的值,而是將指針p的指向改成y;

2、經(jīng)過指針的思考后,我們看看關于引用的思考

int x = 1;
int& f = x;
int y = 0;
f = y;    // 思考一下這一行的作用,是改變了引用f的綁定嗎?

上面這行代碼并不改變f的綁定,而是改變了f的值,同時引用對象x的值也發(fā)生改變;

3、經(jīng)過了指針和引用的思考

下面思考下兩者在底層有什么關聯(lián):

int x;
int* p = &x; *p = 1;
int& f = x; f = 1;

分析下上面兩行代碼,他們底層實現(xiàn)會相同嗎?

在這里插入圖片描述

這是兩者的匯編代碼實現(xiàn),可以發(fā)現(xiàn)是完全相同的,引用底層也是通過指針實現(xiàn)的;

4、思考以下代碼中&x是什么數(shù)據(jù)類型?

int x = 1;
const int* p = &x;

如果我們只考慮&x的話,這是一個int*的類型,但由于第二行代碼執(zhí)行拷貝構造,隱式地將&x轉換為左值所需要的 const int *類型;

5、思考下面函數(shù)傳參的區(qū)別?

void fun(int x){}
void fun(const int& x){}

從本質上來說,上面兩種傳參實現(xiàn)的作用是一致的,第一個進行拷貝構造傳遞,所以在函數(shù)內(nèi)部無法改變外部x變量的值,而下面的傳參傳入引用可以在函數(shù)內(nèi)部改變外部x的值,加入const強制成變量;第二種其實是畫蛇添足地做法,但常量引用對于復雜的數(shù)據(jù)類型來說,是能夠節(jié)省很多空間的,比如自定義的結構體;

6、下面常量表示底層常量還是頂層常量?

using mytype = int*;
int x = 1;
const mytype p = &x;

這里我們?nèi)菀渍`導,還會認為這是一個底層常量,但由于別名的定義,這里其實是一個頂層常量,我們可以將mytype看作一個整體,那么指針的指向不可發(fā)生改變;

7、下面auto&自動推導出的y是什么類型?

const int x = 1;
auto& y = x;

相信大部分人會認為x會類型退化,從而y為int&類型,實際上這里類型不會退化,所以y為const int&類型;

8、下面來看看decltype自動推導的類型是什么?

int x = 1;
decltype(x);  // 1 
decltype((x));  // 2

decltype在傳入?yún)?shù)為左值時加入引用,那么第一行為一個變量,所以為int類型,第二行為表達式,所以加入引用為int&類型;

總結:

本篇講解的類型知識點很雜,并且涵蓋很多小的知識點,很多細節(jié)部分在實際工程中不一定會接觸到,當然在工程中也會遇到很多自己不理解的類型轉換,需要多通過debug模式來查看類型;

本篇知識點較多,可以選擇自己想了解的部分進行查看,后續(xù)會繼續(xù)推出更深層次的內(nèi)容;

原文鏈接:https://blog.csdn.net/weixin_40620310/article/details/121285344

欄目分類
最近更新