,
演算子は C で何をしますか?
8 に答える
表現:
(expression1, expression2)
最初に expression1 が評価され、次に expression2 が評価され、式全体に対して expression2 の値が返されます。
私はwhile
ループで最も使用されているのを見てきました:
string s;
while(read_string(s), s.len() > 5)
{
//do something
}
操作を行い、副作用に基づいてテストを行います。もう1つの方法は、次のようにすることです。
string s;
read_string(s);
while(s.len() > 5)
{
//do something
read_string(s);
}
コンマ演算子は左側のオペランドを評価し、結果を破棄してから右側のオペランドを評価し、それが結果になります。リンクに記載されている慣用的な使用法は、ループで使用される変数を初期化する場合でfor
あり、次の例を示します。
void rev(char *s, size_t len)
{
char *first;
for ( first = s, s += len - 1; s >= first; --s)
/*^^^^^^^^^^^^^^^^^^^^^^^*/
putchar(*s);
}
それ以外の場合、コンマ演算子の優れた使用法はあまりありませんが、読みにくく、維持しにくいコードを生成するために乱用するのは簡単です。
ドラフト C99 標準の文法は次のとおりです。
expression:
assignment-expression
expression , assignment-expression
そしてパラグラフ2は言う:
コンマ演算子の左側のオペランドは void 式として評価されます。その評価の後にシーケンス ポイントがあります。次に、右側のオペランドが評価されます。結果には型と値があります。 97)コンマ演算子の結果を変更したり、次のシーケンス ポイントの後にアクセスしようとした場合の動作は未定義です。
脚注 97は次のように述べています。
コンマ演算子は左辺値を生成しません。
つまり、コンマ演算子の結果に割り当てることはできません。
コンマ演算子は優先順位が最も低い()
ため、使用することで大きな違いが生じる場合があることに注意することが重要です。次に例を示します。
#include <stdio.h>
int main()
{
int x, y ;
x = 1, 2 ;
y = (3,4) ;
printf( "%d %d\n", x, y ) ;
}
次の出力が得られます。
1 4
コンマ演算子は、両側の 2 つの式を 1 つに結合し、両方を左から右の順序で評価します。右辺の値は、式全体の値として返されます。
(expr1, expr2)
は似ていますが、関数呼び出しまたは代入で{ expr1; expr2; }
の結果を使用できます。expr2
次のように、複数の変数を初期化または維持するループでよく見られfor
ます。
for (low = 0, high = MAXSIZE; low < high; low = newlow, high = newhigh)
{
/* do something with low and high and put new values
in newlow and newhigh */
}
これとは別に、マクロで常に一緒に実行する必要がある 2 つの操作をまとめるときに、別の 1 つのケースで「怒って」使用しただけです。ネットワーク上で送信するためにさまざまなバイナリ値をバイト バッファーにコピーするコードと、取得した場所にポインターを保持するコードがありました。
unsigned char outbuff[BUFFSIZE];
unsigned char *ptr = outbuff;
*ptr++ = first_byte_value;
*ptr++ = second_byte_value;
send_buff(outbuff, (int)(ptr - outbuff));
値がshort
s またはint
s の場合、次のようにしました。
*((short *)ptr)++ = short_value;
*((int *)ptr)++ = int_value;
後で、これは実際には有効な C ではないことを知りました。これは(short *)ptr
、l 値ではなく、インクリメントできないためです。ただし、当時のコンパイラは気にしませんでした。これを修正するために、式を 2 つに分割します。
*(short *)ptr = short_value;
ptr += sizeof(short);
ただし、このアプローチは、すべての開発者が常に両方のステートメントを入れることを覚えていることに依存していました。出力ポインタ、値、および値の型を渡すことができる関数が必要でした。これはテンプレートを使用した C++ ではなく C であるため、関数に任意の型を指定することはできなかったため、マクロに落ち着きました。
#define ASSIGN_INCR(p, val, type) ((*((type) *)(p) = (val)), (p) += sizeof(type))
コンマ演算子を使用することで、これを式またはステートメントとして必要に応じて使用できました。
if (need_to_output_short)
ASSIGN_INCR(ptr, short_value, short);
latest_pos = ASSIGN_INCR(ptr, int_value, int);
send_buff(outbuff, (int)(ASSIGN_INCR(ptr, last_value, int) - outbuff));
これらの例のどれもが良いスタイルだと言っているわけではありません! 実際、Steve McConnell のCode Completefor
で、ループ内でコンマ演算子を使用することさえ避けるべきであるとアドバイスしたことを覚えているようですfor
。他の余分な初期化やループ メンテナンスはありません。
複数のステートメントの評価を引き起こしますが、結果の値として最後のステートメントのみを使用します (右辺値だと思います)。
そう...
int f() { return 7; }
int g() { return 8; }
int x = (printf("assigning x"), f(), g() );
x が 8 に設定されるはずです。
以前の回答で述べたように、すべてのステートメントを評価しますが、最後のステートメントを式の値として使用します。個人的には、ループ式でのみ役立つことがわかりました。
for (tmp=0, i = MAX; i > 0; i--)
私がそれが役立つと思った唯一の場所は、式の1つ(おそらくinit式またはloop式。次のようなもの)で複数のことを実行したいファンキーなループを作成するときです。
bool arraysAreMirrored(int a1[], int a2[], size_t size)
{
size_t i1, i2;
for(i1 = 0, i2 = size - 1; i1 < size; i1++, i2--)
{
if(a1[i1] != a2[i2])
{
return false;
}
}
return true;
}
構文エラーがある場合、または厳密でないCを混在させた場合は、ご容赦ください。、演算子が適切な形式であるとは主張していませんが、それを使用できます。上記の場合、おそらくwhile
代わりにループを使用するので、initとloopの複数の式がより明白になります。(そして、宣言してから初期化する代わりに、i1とi2をインラインで初期化します。....何とか何とか何とか。)
@Rajesh と @JeffMercado からの質問に対処するためだけにこれを復活させます。これは検索エンジンのトップ ヒットの 1 つであるため、非常に重要だと思います。
たとえば、次のコード スニペットを見てください。
int i = (5,4,3,2,1);
int j;
j = 5,4,3,2,1;
printf("%d %d\n", i , j);
印刷します
1 5
ケースは、i
ほとんどの回答で説明されているように処理されます。すべての式は左から右の順序で評価されますが、最後のものだけが に割り当てられi
ます。(
式) is
1`の結果。
演算子の優先順位が最も低いためj
、ケースは異なる優先規則に従います。,
これらの規則により、コンパイラは代入式、定数、定数 ... を認識します。式は再び左から右の順序で評価され、その副作用は表示されたままです。したがって、j
の5
結果ですj = 5
。
興味深いことに、int j = 5,4,3,2,1;
言語仕様では許可されていません。初期化子は代入式を想定しているため、直接,
演算子は使用できません。
お役に立てれば。