C語言左值和右值,以及操作符屬性總結

2021-06-18 00:40:45 字數 3184 閱讀 9718

《c和指標》這本書上講到左值和右值,概念有點含糊

據我自己的理解:

左值:標識的應該是個儲存位置,記憶體中的位置,左值可以是個變數名,或者是個表示式,但表示式必須表示的是個記憶體位置

右值:就是個值,變數的值,表示式的值

操作符的屬性有3個因素:操作符的優先順序操作符的結合性操作符是否控制執行順序

操作符的優先順序:決定含有多個操作符的表示式的求值順序,每個操作的優先順序不同

操作符的結合性:決定相同優先順序的操作符是從左到右計算,還是從右到左計算。

操作符是否控制執行順序:對表示式的求值順序施加控制,有4個:&&(邏輯與)  ||(邏輯或)  ?:(條件操作)  ,(逗號運算子)

注1:lexp表示左值表示式,rexp表示右值表示式,l-r表示從左到右求值,r-l表示從右到左求值

注2:左值同樣可以作為右值,但右值卻不能作為左值用

1. ()  聚組

聚組就是加括號對表示式的計算優先順序施加影響,這個是經常用到的,優先順序最高,最先計算聚組內的值,如(5+3),結果與表示式的值相同,也就是同5+3,聚組肯定可以表示乙個右值,因為 a=(5+3) 這個表示式的正確的,聚組可以表示右值,但聚組能否表示乙個左值,如(a)=5+3; (b[5]) = 5+3; 這兩個表示式能合理通過編譯,證明了聚組可以表示為左值,所以正如圖上所述:聚組的結果型別,與表示式的結果型別相同,表示式若表示的是個左值則聚組就表示的是個左值,表示式若表示是個右值則聚組就表示是個右值。

2. () 函式呼叫

函式呼叫的用法示例:rexp(rexp,...,rexp),說明函式名是個右值,而且函式名單獨作為右值使用表示的是執行這個函式的位址,這個位址在編譯完成就確定其位址,不能對函式名表示的位址值就行修改,如:int func() 這個函式,func就表示乙個右值,不能表示為左值,也就是不能用 func=...,估計沒人會這樣用,如果定義乙個指標 int (*f)() = func; 然後通過 (*f)() 來呼叫函式,這個(*f)表示為乙個聚組,返回的值是*f的型別,是個左值,同樣可以作為右值用,同函式呼叫rexp(rexp,...,rexp)不衝突,函式呼叫不限制rexp必須是函式名,可以是任何表示式,如:將函式指標定義到結構體中,然後通過結構體變數來訪問函式指標。需要通過聚組來提高表示式的優先順序。

函式呼叫的引數:全是右值,正是說明了函式呼叫都是傳值的,當然傳遞的左值到函式引數時都會全部轉變成右值。如:int a=10;  func(a); 這裡a就變成了右值

函式呼叫的結果型別:也是右值,就說明了函式只能返回值,不能這樣用:func() = a;

函式呼叫的結合性:l-r,因為找不到和函式呼叫相同優先順序的表示式,這裡就不過多說明。

3. 下標引用

下標引用的用法示例:rexp[rexp],說明陣列名是個右值,如:int a[10]; a[5] = 5; 不能使用a = 5;這樣的表示式,陣列名也是編譯後確定記憶體位址的,陣列名只能做右值,看看這個:int a[10]; int *p = &a; 這麼用是合法的,與int *p=a表示的是乙個意思,但是會警告,對陣列名取位址,&a表示式返回的型別就變成了指向陣列這一塊記憶體的指標,而不是指向陣列中單個元素的指標,所以與p的型別不同,就會警告,然而取位址符的用法:&lexp要求是個左值表示式,似乎好像陣列名a又可以解釋為左值,所以陣列名到底是左值還是右值,要依據上下文環境而定,若是下標引用a 則陣列名是個右值,若是取位址&a 則陣列名是個左值,但是陣列的索引就必定是個右值了。

下標引用的左結合性也是理所當然:如,int a[10][10]; a[5][5] = 5; 這裡有兩個相同優先順序的下標引用,所以必定是先計算出a[5],作為右值,然後再計算出a[5][5],作為左值,然後才賦值。

4. . 訪問結構成員

lexp.member_name,看來定義的結構體變數是作為左值,因為結構體變數是有儲存位址的,而其訪問成員的結果型別也是作為左值,因為成員變數也是有儲存位址的,結合性從左到右,如 a.b.c 這樣的成員訪問,是先訪問結構體a的成員b再訪問b的成員c,所以必定為左結合性。

5. -> 訪問結構體指標成員

rexp->member_name,也就是說執行結構體的指標變數其本身是個左值,有儲存位址,但是訪問成員時就作為右值來用了,其餘的同訪問結構成員

6. ++ -- 字尾自增和自減

lexp++  lexp-- 是個左值,字尾自增和自減的原意就是加完和減完後還要存回原來的地方,暗含了個儲存位址,既然是左值表示式,則 (下標引用)  .(訪問結構成員)  ->(訪問結構體指標成員)  *(間接訪問)  都可以作為自增自減的表示式。

返回的結果型別是個右值,就不能再進行自加或自減了,如:(lexp++)++  這麼做完全是錯誤的。

結合性:由於自加自減不可能會多次呼叫,沒太大意義

7. ! ~ + - 邏輯反 按位反 正值 負值

這四個要求的全部都是右值表示式,返回的值也都是右值,還是右結合性的,也就是說如下用法都可以: !rexp(rexp,...,rexp);  +-lexp++;  -*rexp;  +sizeof rexp;  ~func();

右結合性即:+-lexp++ 等同於 +(-(lexp++))

8. ++ -- 字首自增和自減

同字尾的自增和自減的形式

9. * 間接訪問

* rexp ; rexp是乙個指標變數或者乙個指標表示式,如:*p;  *p++;  *func();  * a[5];  *rexp->member;  *rexp->member++; *++rexp.member;

右結合性要求:*****p 等同於 *(*(*(*(*p))));

10. & 取位址

&rexp.member;  &rexp->member;  注:紅色標註的是個錯誤的語法

11. sizeof (型別)

右結合性:sizeof sizeof sizeof rexp 就等同於 sizeof ( sizeof (sizeof rexp)))

(型別)(型別)(型別)rexp 等同於 (型別) ( (型別) ( (型別)rexp ) )

12. 其餘的運算子由於比較簡單不再討論。

總結:能產生左值的表示式就4個:(下標引用)  .(訪問結構成員)  ->(訪問結構體指標成員)  *(間接訪問) 

C語言左值和右值,以及操作符屬性總結

c和指標 這本書上講到左值和右值,概念有點含糊 據我自己的理解 左值 標識的應該是個儲存位置,記憶體中的位置,左值可以是個變數名,或者是個表示式,但表示式必須表示的是個記憶體位置 右值 就是個值,變數的值,表示式的值 操作符的屬性有3個因素 操作符的優先順序,操作符的結合性,操作符是否控制執行順序。...

C語言左值和右值,以及操作符屬性總結

左值 標識的應該是個儲存位置,記憶體中的位置,左值可以是個變數名,或者是個表示式,但表示式必須表示的是個記憶體位置 右值 就是個值,變數的值,表示式的值 操作符的屬性有3個因素 操作符的優先順序,操作符的結合性,操作符是否控制執行順序。操作符的優先順序 決定含有多個操作符的表示式的求值順序,每個操作...

C語言左值和右值

左值可以標記乙個儲存的位置,右值可以指定乙個值。l value中的l指的是location,表示可定址。the l in lvalue can be though of as location r value中的r指的是read,表示可讀。the r in rvalue can be thought...