C演算子(下)

まず、左と右の値の値

左(L値)の値及び右の値(R値)との差を理解する必要があり、いくつかの演算子に存在する制限を理解します。彼らは厳密にはC言語の定義に適合していないが、これらの2つの用語は、コンパイラの設計者が、まだ使用されて数年前に作成されます。

左の値は、それらのものは、代入の左側に表示されることがあります。右の値が代入の右側に表示することができますそれらのものです。李の場合:

A = B + 25。

それは、結果値の位置が記憶されてもよい特定するように値が残され、B + 25は、それが値として指定され、正しい値です。

彼らはそれを交換することができますか?

B + 25 =。

位置も値が含まれているため、この時点での正しい値として、左の前の値は、であってもよいです。しかし、B + 25の値として残されていません。それはしていないため、特定の場所を特定しますしたがって、この割り当ては違法です。

B + 25を計算するとき、それは必然的な結果は、マシンのどこかに保存されます。しかし、プログラマは結果が所定の位置に格納されるかを予測することはできません、この式の次の値もその場所に保存されている保証はありません。その結果、この式は左辺値ではありません。同じ理由で、またないリテラル定数値は左。

左の式の値のように聞こえるかもしれ変数は値として残すことはできないが、推論は正確ではありません。次の割り当てでは、左の式の値です。

INT [30]。

...

[B + 10] = 0;

左の式は、実際に式であるので、添字参照は、実際には、オペレータが、それがあるため、正当左値であり、それは特定の場所を識別する、我々はそれを参照して後、プログラムを再ことができます。ここで栗を引用:

、* pはint型。

...

P =&;

* P = 20。

二代入文は、その左の値は明らかに式ですが、それはまた、法的な左辺値です。ポインタpの値は、特定のメモリ位置のアドレスであるため、機械のオペレータは、*それは左の値として使用される位置を指すように、指定位置の必要性の発現が変更されます。そのまま右の値が使用される場合、それは現在の場所に格納された値を検索します。

いくつかの演算子は、このような間接的なアクセス(*)及び参照インデックス([])、その結果を左の値です。結果の剰余演算子は、右辺値です。

 

第二に、式の評価

発現は、優先の評価順序の一部が結合して、オペレータが含まれていることによって決定されます。同一のオペランドのいくつかの発現は、評価プロセスの他の型に変換することができます。

1.暗黙の型変換

C整数演算は、デフォルトの整数型(デフォルトタイプ)少なくとも精度に常にあります。この精度を得るために、短い整数オペランドと文字表現は、通常の整数として使用する前に変換され、この変換は、積分プロモーション(積分プロモーション)と呼ばれています。たとえば、

チャーA、B、C。

...

A = B + C。

B及びCの値は一般的な整数に昇格され、その後、加算演算が行われます。加算結果は切り捨てられ、その後媒体に格納されます。本実施例の結果と8ビットの演算結果を用いても同様です。ただし、次の例では、それはもはや同じ結果ではありません。この例では、簡単なテストや一連の文字を計算するために使用されます。

=(〜^ B << 1)>> 1。

補体と左シフト演算が存在するので、8ビットの精度に起因は十分ではありません。完全な標準の整数を評価、そのような表現の結果は、あいまい存在しません。(標準、結果はコンパイラが最終的な結果には影響しない8ビットの精度を使用して評価知っている場合、それは、求めて整数を完了する価値があるべき説明し、それはまた、コンパイラがそうすることができます)。

2.算術変換

オペランドの一方が、操作の数の別のタイプに変換されない限り、各オペランド異なるタイプのオペレータは、そうそうでなければ操作を行うことができない場合。次の階層は、通常の算術変換(通常の算術変換)と呼ばれます。

長い二

ダブル

浮く

符号なしlong int型

long int型

unsigned int型

int型

上記下位ランクの動作の数のタイプの場合は、最初の操作の別の型に変換した後、操作の数を実行します。

3.オペレータプロパティ

評価の順序は、三つの要因の複雑な式によって決定される演算子の優先順位と結合オペレータのオペレータが実行の順序を制御するかどうか。その優先順位に応じて、どの郡実行の両方が同じ優先順位を持っている場合、その後、その実行順序は、それらの結合によって決まる。隣接する2つの事業者 簡単に言えば、結合性は、事業者の束が右または実行その逆に左から実行されています。最後に、4つの事業者が存在し、彼らは他のすべてのサブ式の評価プロセスが完了する前に、それはまた、Aを作ることが評価できることを保証する表現、式全体の評価の順序を制御するために適用することができます式はスキップされ、評価されませんでした。

各演算子のすべてのプロパティは、次の優先順位の表に記載されています。テーブルの列は演算子を表し、それが発現制御配列の評価が適用される場合、それは次のようになりとき短時間、使用例、結果のタイプ、結合が発生しています。それは左のオペランド値を必要とするかどうかの使用例のヒント。用語lexp(左式)式の右側の値をrexp、左側の値式を表します。値は左の位置を意味し、正しい値が値を意味し、覚えておいてください。だから、右の数値を使用する代わりに、あなたはまた、左の値を使用することができます。しかし、現地のニーズの左辺値は正しい値を使用することはできません。

4.優先順位と評価さ

複数のオペレータの発現は、行うこれらの演算子の実行順序を決定するものである場合には?答えが優先され、各オペレータCは、オペレータ表現の残りの部分との間の関係を決定するための優先順位を有しています。しかし、それだけでは評価の優先順位を決定することはできません。ここではその基本的なルールは以下のとおりです。

二つの隣接するオペレータの実行の順序は、それらの優先順位によって決定されます。彼らは同じ優先順位を持っている場合は、その実行順序は、それらの結合によって決まります。また、コンパイラは自由に限り、それはコンマに違反しないとして、評価された式の任意のシーケンスを使用することを決定することができ、&&、||、そして?:制限事項は、オペレータを課しました。

換言すれば、発現オペレータは、評価プロセスにおけるポリ方法の発現の様々な構成要素の優先順位を決定します。例えば:

+ B * C

この式では、加算と乗算演算子は、2つの隣接する演算子です。演算子* +演算子よりも高い優先ので、乗算演算は、添加前に行います。ここでは、コンパイラは選択の余地を持っていない、それは第1の乗算を実行する必要があります。

ここではより興味深い式は次のとおりです。

* B + C * D + E * F

如果仅由优先级决定这个表达式的求值顺序,那么所有三个乘法运算将在所有加法运算之前进行。事实上,这个顺序并不是必需的。实际上只要保证每个乘法运算在它相邻的加法运算之前进行即可。例如,这个表达式可能会以下面的顺序进行,其中粗体的操作符表示在每个步骤中进行操作的操作符。

a * b

c * d

(a*b) + (c*d)

e * f

((a*b)+(c*d)) + (e*f)

注意第一个加法运算在最后一个乘法运算之前进行。如果这个表达式按以下顺序执行,其结果是一样的。

c * d

e * f

a * b

(a*b) + (c*d)

((a*b)+(c*d)) + (e*f)

加法运算的结合性要求两个加法运算按照先左后右的顺序执行,但它对表达式剩余部分的执行顺序并未加以限制。尤其是,这里并没有任何规则要求所有的乘法运算首先执行,也没有规则规定这几个乘法运算之间谁先执行。优先级规则在这里起不到作用,优先级只对相邻操作符的执行顺序起作用。

警告:

由于表达式的求值顺序并非完全由操作符的优先级决定,所以像下面这样的语句是很危险的。

c + --c

操作符的优先级规则要求自减运算在加法运算之前进行,但我们并没有办法得知加法操作符的左操作数是在右操作数之前还是之后进行求值。它在这个表达式中将存在区别(二义性),因为自减操作符具有副作用。--c和c之前或之后执行,表达式的结果在两种情况下将会不同。

标准说明类似这种表达式的值是未定义的。尽管每种编译器都会为这个表达式产生某个值,但到底哪个是正确的并无标准答案。因此,这样的表达式应该避免。

同样的,下面这个表达式说明了一个相关的问题。

f() + g() + h()

尽管左边那个加法运算必须在右边那个加法运算之前执行,但对于各个函数调用的顺序,并没有规则加以限制。如果它们的执行具有副作用,比如执行一些I/0任务或修改全局变量,那么函数的调用顺序的不同可能会产生不同的结果。因此,如果顺序导致结果产生区别,你做好使用临时变量,让每个函数调用都在单独的语句中进行。

temp = f();

temp += g();

temp += h();

 

总结

C具有丰富的操作符。算术操作符包括+(加)、-(减)、*(乘)、/(除)、%(取模)。除了%之外,其余的操作符不仅可以作用于整型还可以作用于浮点型。

<<和>>操作符分别执行左移位和右移位操作。&、|和^分别执行与、或和异或操作。这几个操作符都要求其操作数为整型。

=操作符执行赋值操作。而且,C还存在复合赋值符,它将赋值符和前面的操作符结合在一起:

+=        -=     *=     /=     %=

<<=    >>=   &=   ^=     |=

复合赋值符在做右操作数之间执行指定的运算,然后把结果赋值给左操作数。

单目运算符包括!(逻辑非)、~(按位取反)、-(负)、+(正)、++和--操作符分别用于增加或减少操作数的值。这两个操作数有前缀和后缀形式。前缀形式在操作数的值被修改之后才返回这个值,而后缀形式在操作数的值被修改之前就返回这个值。&操作符返回一个指向它的操作数指针(取地址),而*操作符对它的操作数(必须为指针)进行间接访问操作。sizeof返回操作数的类型的长度,以字节为单位。最后,强制类型转换(cast)用于修改操作数的数据类型。

关系操作符有:

>     >=     <     <=     !=    ==

每个操作符根据它的操作数之间是否存在指定的关系,或返回真,或返回假。逻辑操作符用于计算复杂的布尔表达式。对于&&操作符,只有当它的两个操作数都为真时,它的值才是真;||操作符,只有它的两个操作数都为假时,它的值才是假。这两个操作符会对包含它们的表达式的求值过程施加控制。如果整个表达式的值通过左操作数便可确定,那么右操作数便不再求值。

条件操作符?:接受三个参数,它也会对表达式的求值过程施加控制。如果第一个操作数的值为真,那么整个表达式的结果就是第二个操作数的值,第三个操作数不会执行。否则结果是第三个操作数的值,第二个操作数不会执行。逗号操作符把两个或更多的表达式连接在一起,从左向右一次进行求值,整个表达式的值就是最右边的子表达式的值。

左值是个表达式,它可以出现在赋值符的左边,它表示计算机内存中的一个位置。右值表示一个值,所以它只能出现在赋值符的右边。每个左值表达式同时也是个右值,但反过来就不是这样。

各个不同类型之间不能直接进行运算,除非其中之一的操作数转换为另一操作数的类型。寻常算术转换决定哪个操作数将被转换。操作符的优先级决定了相邻的操作符哪个先被执行。如果它们的优先级相等,那么它们的结合性将决定它们执行的顺序。但是,这些并不能完全决定表达式的求值顺序。编译器只要不违背优先级和结合性规则,就可以自由决定复杂表达式的求值顺序。表达式的结果如果依赖于求值的顺序,那么它在本质上是不可移植的,应避免使用。


发布了60 篇原创文章 · 获赞 18 · 访问量 2万+

おすすめ

転載: blog.csdn.net/BadAyase/article/details/101279014