「飛ばなければ空へ、歌わなければ超大作になる。」今日はオペレーターについて学びましょう。
演算子の詳しい説明
1. 事業者の分類
算術演算子
+ - * / %
シフト演算子<< >>
ビット演算子 代入& | ^
演算子= += -= *= /=...
単項演算子! sizeof ++ -- ...
関係演算子> >= < <= == !=
論理演算子&& ||
条件演算子カンマ式? :
添字,
参照、関数呼び出し、および構造体メンバー[] () ->
2. 算術演算子
+ - * / %
注
%
: 1.演算子に加えて、他のいくつかの演算子が整数と浮動小数点数に作用します。
2./
演算子の場合、両方のオペランドが整数の場合、整数の除算が実行されます。そして、浮動小数点数が存在する限り、浮動小数点数の除算が実行されます。
3.%
演算子の2 つのオペランドはintegers である必要があり、整数除算後の剰余が返されます。
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
int main()
{
int m = 7 / 2;
printf("%d\n", m);
double n = 7.0 / 2;
printf("%lf\n", n);
int o = 7 % 2;
printf("%d\n", o);
return 0;
}
3. シフト演算子
>>右移操作符 <<左移操作符
注: シフト演算子のオペランドには整数のみを指定できます。
整数の場合、4 バイト = 32 ビットです。整数をバイナリ シーケンスとして書き込むと、その整数は 32 ビットになります。符号付き整数の場合、最上位ビットは符号ビットです。符号位是1表示负数,符号位是0表示正数。
符号なし整数の場合、符号ビットはなく、すべてのビットが有効ビットです。
整数のバイナリ表現には、元のコード、逆コード、補数コードの 3 つがあります。
元のコード: 値の符号に従って、直接書き込まれたバイナリ シーケンスが元のコードです。
例:10
この数値原码
は00000000000000000000000000001010
、-10
元のコードは です10000000000000000000000000001010
。
注: 正の整数の場合、元のコード、逆コード、補数コードは同じであるため、計算は必要ありません。
負の整数の場合は、元のコード、逆コード、補数コードを計算する必要があります。
逆コード: 元のコードの符号ビットは変更されず、他のビットはビットごとに反転されます。(ビット反転、元の0を1に、元の1を0に変更)
補数符号:反転符号の2進数+1が補数符号です。
したがって、10
この数は原码、反码、补码
すべて です00000000000000000000000000001010
。-10
元のコードは10000000000000000000000000001010
、逆コードは11111111111111111111111111110101
、補数コードは です11111111111111111111111111110110
。整数は 2 の補数のバイナリ シーケンスとしてメモリに格納されます。整数を計算する場合は、2 の補数が使用されます。
3.1 左シフト演算子
シフト ルール: 左側を破棄し、右側に 0 を追加します。
#include <stdio.h>
int main()
{
//m:00000000000000000000000000000111
int m = 7;
int n = m << 1;
//左移位原则:左边抛弃,右边补0
//n:00000000000000000000000000001110
//n = 2+4+8=14
printf("%d\n", m);
printf("%d\n", n);
return 0;
}
左シフト演算子が 2 つの役割を果たすことができることがわかります。負の数にも同じことが当てはまります。
3.2 右シフト演算子
シフト規則 (右シフト演算には 2 種類あります):
1. 論理シフト: 左側は 0 で埋められ、右側は破棄されます。
2. 算術シフト: 左側は元の値の符号ビットで埋められ、右側は破棄されます。
//右移位操作符
#include <stdio.h>
int main()
{
//a的原码:10000000000000000000000000001010
//a的反码:11111111111111111111111111110101
//a的补码:11111111111111111111111111110110
//大多数编译器采用的是算术右移
//b是算术右移(右边直接丢弃,左边补原符号位,原来是负数,左边补1,原来是正数,左边补0)
//b的补码:11111111111111111111111111111011
//b的反码:11111111111111111111111111111010
//b的原码:10000000000000000000000000000101
//b=-(1+4)=-5
int a = -10;
int b = a >> 1;
printf("a=%d\n", a);
printf("b=%d\n", b);
return 0;
}
/2
算術右シフトも役割を果たしていることがわかります。
注: シフト演算子の場合、負のビットをシフトしないでください。これは標準では定義されていません。
4. ビット演算子
ビット単位の演算子は次のとおりです。
|(按位或)&(按位与)^(按位异或)
注: これらのオペランドは整数である必要があります。
4.1 ビット単位の AND&
2 つの数値の場合はa和b
、ビットごとの AND 演算子を使用します。最初に 2 進数ビットの補数形式をc = a&b;
記述してから、それらを 1 つずつ比較する必要があります。a和b
只有当两个数a和b的对应的补码都为1的时候,按位与的结果才是1,否则为0。
#include <stdio.h>
int main()
{
int a = 3;
int b = -5;
int c = a & b;//按(二进制)位与
//-5的原码:10000000000000000000000000000101
//-5的反码:10000000000000000000000000000100
//-5的补码:11111111111111111111111111111011
// 3的补码: 00000000000000000000000000000011
// 按位与:两个都为1才为1
// c: 00000000000000000000000000000011
//结果为3
printf("%d\n", c);
return 0;
}
4.2 ビットごとの OR |
2 つの数値の場合はa和b
、ビット単位の OR 演算子を使用します。最初に 2 進数ビットの補数形式をc = a|b;
記述してから、それらを 1 つずつ比較する必要があります。a和b
只要当两个数a和b的对应的补码有一个为1的时候,按位或的结果就是1,否则为0。
#include <stdio.h>
int main()
{
int a = 3;
int b = -5;
int c = a | b;//按(二进制)位或
//-5的原码:10000000000000000000000000000101
//-5的反码:10000000000000000000000000000100
//-5的补码:11111111111111111111111111111011
// 3的补码: 00000000000000000000000000000011
// 按位或:有一个为1即为1
// c的补码: 11111111111111111111111111111011
// c的反码: 11111111111111111111111111111010
// c的原码: 10000000000000000000000000000101
//结果为-5
printf("%d\n", c);
return 0;
}
4.3 ビットごとの XOR^
2 つの数値の場合はa和b
、ビット単位の OR 演算子を使用します。最初に 2 進数ビットの補数形式をc = a^b;
記述してから、それらを 1 つずつ比較する必要があります。a和b
两个数a和b的对应的补码相同为0,不同为1.
#include <stdio.h>
int main()
{
int a = 3;
int b = -5;
int c = a ^ b;//按(二进制)位异或
//-5的原码:10000000000000000000000000000101
//-5的反码:10000000000000000000000000000100
//-5的补码:11111111111111111111111111111011
// 3的补码: 00000000000000000000000000000011
// 按位异或:相同为0不同为1
// c的补码: 11111111111111111111111111111000
// c的反码: 11111111111111111111111111110111
// c的原码: 10000000000000000000000000001000
//结果为-8
printf("%d\n", c);
return 0;
}
注: 特に、a^a=0; a^0=a;
.
次に、特別な質問をします。一時変数を作成せず (3 番目の変数は作成しません)、2 つの数値の交換を実現します。
前回の研究により、3 番目の変数の使用方法がわかりました。
//实现两个数的交换
#include <stdio.h>
int main()
{
int a = 3;
int b = 5;
int c = 0;
printf("交换前a=%d,b=%d\n", a, b);
c = a;
a = b;
b = c;
printf("交换后a=%d,b=%d\n",a,b);
return 0;
}
では、3 番目の変数を使用せずに同じ機能を実現するにはどうすればよいでしょうか?
//实现两个数的交换
#include <stdio.h>
int main()
{
int a = 3;
int b = 5;
printf("交换前a=%d,b=%d\n", a, b);
a = a + b;
b = a - b;
a = a - b;
printf("交换后a=%d,b=%d\n", a, b);
return 0;
}
ここでは 2 つの変数のみを使用していますが、まだ欠陥があります。つまり、a和b
の値が非常に大きい場合、オーバーフローの問題が発生します。ここでは、この演算子を使用する必要があります异或^
。
//实现两个数的交换
#include <stdio.h>
int main()
{
int a = 3;
int b = 5;
printf("交换前a=%d,b=%d\n", a, b);
a = a ^ b;//a=3^5;
b = a ^ b;//b=3^5^5=3
a = a ^ b;//a=3^5^3=3^3^5=5
//异或支持交换律
printf("交换后a=%d,b=%d\n", a, b);
return 0;
}
注:异或^
オーバーフローの問題はありませんが、可読性は高くなく、整数演算のみに限定されます。
5. 代入演算子
代入演算子は、変数の作成後に変数の値を変更するために使用されます。
#include <stdio.h>
int main()
{
int a = 3;//不是赋值,是初始化
a = 10;//赋值
return 0;
}
代入演算子は、次のように連続して使用できます。
#include <stdio.h>
int main()
{
int a = 10;
int b = 20;
int c = a = a + b;//连续赋值
//连续赋值从右往左算
//a = a + b = 30
//c = a = 30
printf("%d\n", c);
return 0;
}
ただし、連続代入ステートメントはデバッグには役に立ちません。上記は次のようint c = a = a + b;
に分割できます。
a = a + b;
c = a;
//这样的写法更清晰爽朗且易于调试。
複合代入演算子:
+= -= *= /= %= >>= <<= &= |= ^=
これらの演算子はすべて複合効果として記述することができます。次に例を示します。
int a = 2;
//以下两种写法表达含义一致
a = a + 10;
a += 10;
6. 単項演算子
6.1 単項演算子の概要
単項演算子 | 名前 |
---|---|
! | 論理逆演算子 |
- | 負の値 |
+ | 正の値 |
& | 住所を取る |
のサイズ | オペランドの型の長さ (バイト単位) |
~ | 数値のビット単位の逆数 |
- - | フロントリア - - |
++ | フロント、リア++ |
* | 間接アクセス演算子 (逆参照演算子) |
(タイプ) | キャスト |
1. 論理逆演算子 (!)
//0表示假,1表示真
#include <stdio.h>
int main()
{
int a = 1;
int b = 0;
b = !a;
printf("%d\n", b);
return 0;
}
2. 逆参照演算子 (*)
//解引用操作符*
#include <stdio.h>
int main()
{
int a = 10;
int* p = &a;
*p;//对p解引用操作,*p是通过p中存放的地址,找到p指向的对象
//*p就是a
return 0;
}
3. sizeof と配列
//sizeof计算的是类型创建变量或变量的大小,单位是字节
//sizeof计算的结果是size_t类型的
//size_t是无符号的
//对size_t类型的数据进行打印,可以用%zd
//sizeof后面的括号在括号中写的不是类型的时候,括号可以省略,这样也说明了sizeof不是函数
//sizeof是操作符-单目操作符
#include <stdio.h>
int main()
{
int a = 10;
printf("%zd\n", sizeof(a));
printf("%zd\n", sizeof a);
printf("%zd\n", sizeof(int));
int arr[10] = {
0 };
printf("%zd\n", sizeof arr);
printf("%zd\n", sizeof(arr[1]));
return 0;
}
4.~ (数値の 2 進反転)
#include <stdio.h>
int main()
{
int a = 0;
printf("%d\n", ~a);
//a的补码: 00000000000000000000000000000000
// 按位取反,就是不论是不是符号位都取反
//~a的补码:11111111111111111111111111111111
//~a的反码:11111111111111111111111111111110
//~a的原码:10000000000000000000000000000001
// 符号位0为正 1为负
//~a的值为-1
return 0;
}
さて、次は~
使い方がわかりますか?
#include <stdio.h>
int main()
{
int a = 10;
//000000000000000000000000000001010
//如果我们想让从右往左数第三个数变成1该怎么做?
// 即变成00000000000000000000000000001110为14
//将000000000000000000000000000000001左移二
//1<<2 00000000000000000000000000000100
//将左移后的二进制位与a的二进制位按位或即可
a |= (1 << 2);
printf("%d\n", a);
//那么,反过来,如果希望从右往左数第三个数再变为0该怎么办?
// 只需要将下面第一个和第二个按位与就能得到第三个
//0000000000000000000000000000001110
//1111111111111111111111111111111011,这个可以将(1<<2)取反得到
//0000000000000000000000000000001010
a &= ~(1 << 2);
printf("%d\n", a);
return 0;
}
5.++ --
オペレーター
#include <stdio.h>
int main()
{
int a = 2;
//++a;
//++是一种自增1的操作
a++;
//前置++和后置++对于a本身没有影响,都是进行+1的操作
printf("%d\n", a);
return 0;
}
pre ++ と post ++ は、それ自体には影響を与えませんが、他のものには影響を与えます。例は次のとおりです。
#include <stdio.h>
int main()
{
int a = 2;
int b = a++;
//后置++:先使用,后+1
printf("%d\n", a);
printf("%d\n", b);
return 0;
}
#include <stdio.h>
int main()
{
int a = 2;
int b = ++a;
//前置++:先+1,后使用
printf("%d\n", a);
printf("%d\n", b);
return 0;
}
前置--和后置--和前、后置++同理,大家可以自己试一下!
さて、演算子についての知識はここまでにして、今後も更新していきますので、皆さんも引き続き注目、いいね、コメントお待ちしております!