《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...