C++ Primer 第4章運算符 4.8~4.11

4.8 位運算符

位運算符
位運算符有如上幾個

1.位運算符作用於整型類型的運算對象,把運算對象當做二進制的集合。

2.<<和>>是位移運算符,<<代表左移,>>代表右移,運算對象使用<<往左移動數位,後續補零。符號位是否移動取決於編譯器。同理運算對象使用>>符號,向右按位移動,空白處補零,符號位是否移動取決於編譯器。

3.注意移位運算符要求expr2必須是整數,且不能爲負

4.位求反~,顧名思義,運算對象按位求反

5.位或|,位與&,位異或^,注意,位或是對應位置至少一個爲1,那個位置求得的結果才爲1,位與則是對應位置要都爲1,那個位置求得的結果才爲1,位異或則是,對應位置有且只有一個爲1,那個位置才爲1,其餘情況都是0.和邏輯運算符不一樣,不要弄混了

6.輸入輸出流重載了>>和<<,但是其優先級和結合律都沒有變,位移運算符的優先級低於算術運算符,高於關係、邏輯、條件運算符。位移運算符滿足左結合律。

練習

4.25
假設求值結果還是按照8位計算。那麼移動六位之後,得到的結果是這樣的,超過的部分截取掉,剩下的部分則爲0100 0000,轉化爲十進制位64,查表得對應得符號位@。

https://blog.csdn.net/tenfyguo/article/details/5918142

00000000 00000000 00011100 01000000

4.26

具體還是的看編譯器對int得實現,如果編譯器對int得實現,只佔用16位,則quizl得到的結果一直爲0

4.27
做這種題,首先把變量的二進制形式寫出來,因爲前面多位爲0,所以忽略了,只寫16位

ul1
0000 0000 0000 0011
ul2
0000 0000 0000 0111

a.0000 0000 0000 0011–>3
b.0000 0000 0000 0111 -->7
c.true
d.true

sizeof運算符

1.sizeof運算符用來返回一個類型或者一條表達式所佔的字節數,其返回類型位size_t類型,值得注意的是,它並不會真的執行這個表達式,調用方式有兩種:

sizeof (type)
sizeof expr

2.因爲sizeof並不會真的去計算運算對象(一個類型或者表達式),所以sizeof中可以寫一個類型的無效指針,或者一個類中並沒有實際初始化的數據成員。

Student std,*std_p;
sizeof(*std_p);
sizeof std_p;
sizeof std.score
sizeof Student::score//C++11標準,直接使用作用域符來訪問類中的數據成員

3.對於string和vecotor容器,sizeof獲取到的是他們實際佔用的空間的大小,而不是裏面存儲的元素的所佔的空間

4.sizeof可以獲取數組的大小,等價於將數組中的每個元素都sizeof一次,然後求和。

5.sizeof遵循右結合律

練習

4.28

4.29

一樣= =。。sizeof並不會把指向數組的指針當做數組來對待

4.30
在後面加括號就行,

d不需要加

逗號運算符

1.逗號運算符需要兩個運算對象,其按照從左到右的順序求值,計算結果爲右側運算對象的值,如果右側對象爲左值則最終求值結果爲左值。

int a = 1, b = 2;
int i = 0;
i= (a,b);//輸出結果爲2,解釋如上
cout << i << endl;;

這個我覺得只需要瞭解就好了

練習

4.31
在vs2017編譯環境下,前置和後置並沒有什麼區別。。。

vector<int> ivec(6, 0);
vector<int>::size_type cnt = ivec.size();
for (vector<int>::size_type ix = 0; ix != ivec.size();++ix,--cnt) {
	ivec[ix] = cnt;
}
for (const auto &item:ivec) {
	cout << item << endl;
}

4.32
使用指針ptr遍歷數組中的元素,ix用來判斷是否越界,ptr!=ia+size也是用來判斷是否越界,從邏輯上,ptr!=ia+size沒有必要添加

4.33
如果someValue爲True,則返回++y後的結果,如果someValue爲false,則返回–y後的結果

4.11 類型轉換

int a = 1;
double b = 3.14;
int c = a+b;

爲什麼a+b可以執行,因爲C++語言中存在着類型轉換,類型轉化分爲隱式轉化和顯示轉化。上述的代a+b這裏進行的是隱式轉化,程序員無需知道具體的細節,而顯式轉化則需要程序員自己的來執行。

隱式的轉化被設計爲儘可能的降低精度的損失,所以浮點型和整型在表達式中同時存在的話,最終都會轉化爲浮點型。上述的a被轉化double類型。

轉化爲double類型之後,由於c是int類型,所以a+b的結果還需要被轉化爲int類型。在轉化期間,精度會發生損失,小數點後的數,將被抹去

什麼時候會發生隱式轉化呢?
以下是C++ primer中描述,我寫的是自己更加容易理解的表達方式。

1.比int類型小的類型(表達數字的範圍小的類型)會被轉化爲較大的整型,叫做整型提升(關於整型提升後續再詳解),轉化的類型不一定是int,但是一定是能夠表達其所有值的整型。

2.在if()語句中,表達式會被轉化爲bool類型

3.如上述代碼所示,在初始化的時候,右邊的類型會轉化爲左邊的類型,(如果他們是可以相互轉化的話),同樣賦值語句中,=右邊的值也會被轉化爲左邊的類型

4.如上述代碼,在進行算術運算或者關係運算時,會發生隱式的轉化。

最普遍的是數值的轉化,也就是算術轉化。
算術轉化的兩條準則:
1.類型總是向更寬(擁有更多字節)的類型轉化
2.如果整型和浮點型同時存在,則會將整型轉化爲浮點型

如果兩者有衝突呢?

--vs2017環境下--
long long a = 1;
float b = 3.13;
cout << sizeof(long long) << endl;//8
cout << sizeof (float) << endl;//4
cout << a + b << endl;//輸出結果爲4.13

可以看到如果準則1和2有衝突,則準則2優先。

整型提升

1.比int類型表示的範圍更小的內置數值類型(bool, char ,unsigned char ,short ,signed char,wchar_t,…),在計算表達式是,會先轉化爲int或者能夠表示其範圍的其他整型,比如int,unsigned int,long ,unsigned long,long long;

2.目前我們說的轉化,都是在類型同爲有符號類型或者同爲無符號類型的條件下進行的,那麼如果表達式中既有有符號類型,又有無符號類型怎麼辦呢?

書上寫得比較亂,總結起來就是。

  1. 如果無符號類型的字節數大於或者有符號類型,則有符號類型轉化爲無符號類型
  2. 如果無符號類型的字計數小於有符號類型,則將無符號類型轉化爲有符號類型

練習

4.34

a。fval從float轉化爲bool
b。ival從int轉化爲float,其求值結果從float轉化爲double
c,cval整型提升轉化爲int,ival*cval轉化爲double

4.35

a。發生了,‘a’整型提升to int,然後求值結果轉化爲char
b。發生了,ival–>double,ui–>double ,求值結果–>float
c. 發生了,ui->float ,求值結果–>double
d. 發生了,ival–>flaot , float–>double ,double -->char

除了最常見算術轉換,還有其他的類型的轉換。

包括:
1.數組轉換成指針

int ia[10];
int *ip = ia;//這裏的ia被轉化爲指向int型的指針

我個人的理解:轉化後的ip丟失了begin,end等信息。但是這些信息在原來的ia中是存在的。

使用sizeof(ia),decltype(ia), int (&arr)[10] = ia;時,ia並不會轉化爲指針

2.轉化爲bool類型,這是在if()和while()語句中常見的

3.轉化爲常量

int i ;
const int &j = i;//這裏會將i先轉化爲常量
int k =j;//常量不能轉化爲非常量

4.類類型定義的轉換,類類型怎麼和其他的類型進行轉化由類類型自己確定。比如string類中,C風格的字符串是可以轉化爲string類型的字符串的。

顯式轉換

我們可以顯式轉換將對象強制的轉化爲另一種類型,但是C++並不推薦使用強制轉化,因爲使用強制轉化,很可能意味着代碼存在缺陷。

強制類型轉化由四種方式
轉換的格式爲
cast_name(expression)

1.static_cast,適用於大部分的類型轉化,只要其不包含低層const,(低層const指的是指針所指向的對象爲常量)

2.const_cast,將常量類型轉化爲非常量類型,他的作用也只能是將常量轉化爲非常量類型。

int a = 123;
const int*p = &a;
int *b = const_cast<int*>(p);
*b = 3;
cout<<a<<endl;//輸出結果爲3

最好是不要使用const_cast,定義的常量的原本的意思就是不要改變其值,但是這裏又強制改變,所以後果是不能夠預想的。

3.reinterpret_cast這個強制轉換和低層有關

4.dynamic_cast

學過C語言的都知道,C語言中也是有強制類型轉換的,
type (expr)
(type) expr;
這種舊的轉化方式,根據不同的意思,分別對應着static_cast,const_cast,reinterpret_cast,最好是不要使用舊版的強制類型轉化,因爲轉換的意義不清晰

關於強制類型的具體知識,得到看到了相關部分的內容再補充

練習:

4.36

int a = 3;
double b = 3.14;
a *= static_cast<int>(b);
cout<<a<<endl;

4.37

int i; double d; const string *ps; void *pv; char* pc;

pv = static_cast<void*> (const_cast<string*>(ps));

i = static_cast<int>(*pc);

pv = static_cast<void*>(&d);

pc = static_cast<char*>(pv);

4.38
把表達式j/i轉化爲double類型

發佈了46 篇原創文章 · 獲贊 6 · 訪問量 3116
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章