C中 和 的區別及用法

2021-07-30 05:07:23 字數 1506 閱讀 4693

首先 a->b 的含義是 (*a).b ,所以他們是不同的,不過的確 -> 可以用 * 和 . 實現,不需要單獨乙個運算子。

嗯,我這是說現代的標準化的c 語義上來說, -> 可以用 * 和 . 的組合實現。

早期的 c 有一段時間的語義和現代的 c 的語義不太一樣。

稍微有點彙編的基礎的同學可能知道,在機器碼和彙編的角度來看,不存在變數,不存在 struct 這種東西,只存在暫存器乙個叫做記憶體的大陣列

所以變數,是 c 對記憶體位址的乙個抽象,它代表了乙個位置。舉個例子,c 裡面我們寫:

a = b

其實在彙編的角度來看更像是

*a = *b

其中 a 和 b 各是兩個記憶體位址,是指標。

好,以上是基本背景。

基於這個背景我們討論一下 struct 是什麼,以及 struct 的成員是什麼。

假設我們有

struct point ;

struct point p;

struct point *pp = &p;

從現代語義上講 p 就是乙個結構體物件, x 和 y 各是其成員,嗯。

從彙編的語義上講, p 是乙個不完整的位址,或者說,半個位址,再或者說,乙個指向的東西是虛構出來的位址。而 x 和 y 各是在 point 結構中的位址偏移量。也就是說,必須有 p 和 x 或者 p 和 y 同時出現,才形成乙個完整的位址,單獨的乙個 p 沒有意義

早期的 c 就是在這樣的模型上建立的。所以對早期的 c 而言,*pp 沒有意義,你取得了乙個 struct ,而這個 struct 不能塞在任何乙個暫存器裡,編譯器和 cpu 都無法表達這個東西。

這時候只有 p.x 和 p.y 有意義,它們有真實的位址。

早期的 c 就是這樣乙個看起來怪異的語義,而它更貼近機器的表達。

所以對早期的 c 而言,以下的程式碼是對的:

p.x = 1;

int *a;

a = &(p.x);

而以下程式碼是錯的:

(*pp).x = 1;

因為作為這個賦值的目標位址表示式的一部分, *pp,這個中間結果沒法直譯到機器碼。

所以對早期的 c 而言,對 pp 解引用的操作,必須和取成員的偏移的操作,這兩者緊密結合起來變成乙個單獨的操作,其結果才有意義。

所以早期的 c 就發明了 -> ,表示這兩個操作緊密結合的操作。於是才能寫:

pp->x = 1;

嗯,這就是它存在的歷史原因。

而這個歷史原因現在已經不重要了,現代的符合標準的 c 編譯器都知道 (*pp).x 和 pp->x 是等價的了。

說句題外話, c++ 裡面還發明了 .* 和 ->* 這兩個運算子(注意 ->* 不是單獨的 -> 和 * 並排放的意思),關於為什麼要發明這兩個運算子,而不能直接說 a ->* b 的意思就是 a ->(*b) ,這個就作為課堂作業吧。   

js中 和 的區別及用法

1 可將變數轉換成boolean型別,null undefined和空字串取反都為true。var a null if a else 輸出 2 if a else 輸出 12 常常用來做型別判斷,在第一步 之後再做邏輯取反運算,在js中新手常常會寫這樣臃腫的 判斷變數a為非空 未定義或者非空串才能執...

js中 和 的區別及用法

js中 的用法是比較靈活的,它除了做邏輯運算常常會用!做型別判斷,可以用!與上物件來求得乙個布林值,1 可將變數轉換成boolean型別,null undefined 0和空字串取反都為true,其餘都為false。null true undefined true true 100 false ab...

js中 和 的區別及用法

js中 的用法是比較靈活的,它除了做邏輯運算常常會用!做型別判斷,可以用!與上物件來求得乙個布林值,1 可將變數轉換成boolean型別,null undefined和空字串取反都為false,其餘都為true。1 null true 2 3 undefined true 4 5 true 6 7 ...