C言語の演算子、プラスチックのプロモーションと切り捨て
記事のディレクトリ
序文
1.まず、整数ストレージのメカニズムを理解する必要があります
。2。元のコード、1の補数、および1の補数の関係
。2。(1)元のコード、1の補数、および正の整数の1の補数は次のとおりです。同じため、バイナリ変換を直接実行できます;(2 ^ 32-1正の整数)
2。(2)32ビットの負の整数の最初のビットは符号ビットです(1は負の数を表します);(2 ^ 31-1記号)
例を見てみましょう。たとえば、
最初に-1の補数を次のように
記述します。100000000000 0000 0000 0000 0000 0001 -----元のコード
次に、逆のコードを見つけます:符号ビット変更されないままで、他のビットは反転されて反転コードを取得します
1111 1111 1111 1111 1111 1111 1111 1110 -----
反転コード最後に、反転コード+1は補数を取得し、メモリに格納されているすべての補数は
1111です。 1111 1111 1111 1111 1111 1111 1111 1111 -----補数
3.シェーピングプロモーション、切り捨て
パート1。ビット演算子
(1)ビットごとのAND演算子&:対応する2つの位置の2進数が両方とも1の場合、ビット結果は1になり、それ以外の場合は0になります。次の例を見てください。
int a = 15; //0000 0000 0000 0000 0000 0000 0000 1111 ---15的二进制表示
int b = 19; //0000 0000 0000 0000 0000 0000 0001 0011 ---19的二进制表示
int c = a & b;//0000 0000 0000 0000 0000 0000 0000 0011 ---a&b=3的二进制表示
(2)ビットごとのOR演算子|:対応する2つの位置の2進数が両方とも0の場合、ビット結果は0になり、それ以外の場合は1になります。次の例を見てください。
int a = 15; //0000 0000 0000 0000 0000 0000 0000 1111 ---15的二进制表示
int b = 19; //0000 0000 0000 0000 0000 0000 0001 0011 ---19的二进制表示
int c = a | b;//0000 0000 0000 0000 0000 0000 0001 1111 ---a|b=31的二进制表示
(3)ビット単位のXOR演算子^:対応する2つの位置のバイナリビットが同じ場合、結果は0になり、それ以外の場合は1になります。次の例を見てください。
int a = 15; //0000 0000 0000 0000 0000 0000 0000 1111 ---15的二进制表示
int b = 19; //0000 0000 0000 0000 0000 0000 0001 0011 ---19的二进制表示
int c = a^b; //0000 0000 0000 0000 0000 0000 0001 1100 ---a^b=28的二进制表示
以下は、XORを使用して2つの数値の交換を実現します。
#include <stdio.h>
int main()
{
int a = 10; //0000 0000 0000 0000 0000 0000 0000 1010 ---10的二进制表示
int b = 20; //0000 0000 0000 0000 0000 0000 0001 0100 ---20的二进制表示
a = a^b; //a=0000 0000 0000 0000 0000 0000 0001 1110 ---30的二进制表示
b = a^b; //b=0000 0000 0000 0000 0000 0000 0000 1010 ---10的二进制表示
a = a^b; //c=0000 0000 0000 0000 0000 0000 0001 0100 ---20的二进制表示
printf("a = %d b = %d\n", a, b);
return 0;
}
XORを介した2つの数値の交換はオーバーフローしません。
(4)左シフト演算子<<:シフト規則:左側を放棄し、右側を0で埋めます。次の例を見てください。
int main(){
int a = 19; //00000000000000000000000000010011
int b = a<<1;//00000000000000000000000000100110
printf("%d", b);//输出结果38
return 0;
}
(5)右シフト演算子>>:
シフトルール:最初に、2つの右シフト操作があります。
- 論理シフトは左側が0で埋められ、右側が破棄されます
- 算術シフトの左側は元の値の符号ビットで埋められ、右側は破棄されます
(6)ビット単位の否定演算子〜:数値の2進ビットの場合、ビットが1の場合、結果は0になり、0に変更された場合、結果は1になります。例えば:
int a = 19;//00000000000000000000000000010011
int b = ~a;//11111111111111111111111111101100(内存中的补码)
//11111111111111111111111111101011(反码,即补码-1)
//10000000000000000000000000010100(原码,即反码符号位不变,其余位数取反)
パート2。プラスチックの持ち上げと切り捨て
C整数算術演算は、少なくともデフォルトの整数型の精度で常に実行されます。
この精度を得るために、式の文字と短整数のオペランドは、使用される前に通常の整数に変換されます。この変換は、汎整数拡張と呼ばれます。
//负数的整形提升
char c1 = -1;
变量c1的二进制位(补码)中只有8个比特位:
1111111
因为 char 为有符号的 char
所以整形提升的时候,高位补充符号位,即为1
提升之后的结果是:
1111 1111 1111 1111 1111 1111 1111 1111
//正数的整形提升
char c2 = 1;
变量c2的二进制位(补码)中只有8个比特位:
00000001
因为 char 为有符号的 char
所以整形提升的时候,高位补充符号位,即为0
提升之后的结果是:
0000 0000 0000 0000 0000 0000 0000 0001
整形提升的例子:
//实例1
char a,b,c;
...
a = b + c;
//负数的整形提升
char c1 = -1;
变量c1的二进制位(补码)中只有8个比特位:
1111111
因为 char 为有符号的 char
所以整形提升的时候,高位补充符号位,即为1
提升之后的结果是:
1111 1111 1111 1111 1111 1111 1111 1111
//正数的整形提升
char c2 = 1;
变量c2的二进制位(补码)中只有8个比特位:
0000 0001
因为 char 为有符号的 char
所以整形提升的时候,高位补充符号位,即为0
提升之后的结果是:
0000 0000 0000 0000 0000 0000 0000 0001
//无符号整形提升,高位补0
//实例2
#include<stdio.h>
int main()
{
char a = 0xb6;
short b = 0xb600;
int c = 0xb6000000;
if (a == 0xb6)
{
printf("a");
}
if (b == 0xb600)
{
printf("b");
}
if (c == 0xb6000000)
{
printf("c");
}
return 0;
}
`
例2では、aとbを塑性的に促進する必要がありますが、cを塑性的に促進する必要はありません。a、bを塑性的に促進すると、負の数になるため、式
a0xb6、b0xb600の結果は偽ですが、cは塑性昇格を受けず、式c == 0xb6000000の結果は真です。
プログラム出力の結果は次のとおりです。c
例2:
#include <stdio.h>
int main()
{
char a = -1;
//1000 0000 0000 0000 0000 0000 0000 0001 -----原码
//1111 1111 1111 1111 1111 1111 1111 1110 -----反码
//1111 1111 1111 1111 1111 1111 1111 1111 -----补码
//发生截断
//1111 1111 ----a
//由于要打印整形(%d)格式,所以发生整形提升,前面补充符号位
//1111 1111 1111 1111 1111 1111 1111 1111 -----补码
//1111 1111 1111 1111 1111 1111 1111 1110 -----反码
//1000 0000 0000 0000 0000 0000 0000 0001 -----原码
//a那打印就是-1
signed char b = -1;
unsigned char c = -1;
//1000 0000 0000 0000 0000 0000 0000 0001 -----原码
//1111 1111 1111 1111 1111 1111 1111 1110 -----反码
//1111 1111 1111 1111 1111 1111 1111 1111 -----补码
//发生截断
//1111 1111 ----c
//由于要打印整形(%d)格式,所以发生了整形提升,前面补充符号位,但c是无符号数,所以前面补0
//由于是正数-----补码==反码==原码
//0000 0000 0000 0000 0000 0000 1111 1111
printf("a=%d,b=%d,c=%d", a, b, c); //a= -1 b= -1 c= 255
return 0;
}
例3:
#include <stdio.h>
int main()
{
char a = -128;
//1000 0000 0000 0000 0000 0000 1000 0000 -----原码
//1111 1111 1111 1111 1111 1111 0111 1111 -----反码
//1111 1111 1111 1111 1111 1111 1000 0000 -----补码
//截断
//1000 0000 ----a
//由于要打印无符号整形(%u)格式,所以发生整形提升,前面补充符号位
//1111 1111 1111 1111 1111 1111 1000 0000 -----补码==反码==原码
printf("%u\n", a); //打印的值-----4294967168
return 0;
}
プラスチックの持ち上げと切り捨てについて学習したので、次の質問を書いてみましょう。
トピック1:次のコードはどうなりますか
#include<stdio.h>
int main()
{
unsigned int i;
for (i = 9; i >= 0; i--) //无符号整形恒大于0,所以会死循环
{
//当i变成-1时,把有符号数转变位无符号数为32个1然后一直死循环下棋
//1000 0000 0000 0000 0000 0000 0000 0001 -----原码
//1111 1111 1111 1111 1111 1111 1111 1110 -----反码
//1111 1111 1111 1111 1111 1111 1111 1111 -----补码 -1对应的无符号数
printf("%d\n", i);
}
return 0;
}
符号なし整数は常に0より大きいため、無限にループします。
質問2:次のコードによって出力される値は何ですか
#include<stdio.h>
#include<string.h>
int main()
{
char a[1000];
int i;
/*a是字符型数组,strlen找的是第一次出现尾零(即值为0)的位置。考虑到a[i]其实是字符型,
如果要为0,则需要 - 1 - i的低八位要是全0,也就是问题简化成了“寻找当 - 1 - i的结果第一次出现低八位全部为0的情况时,
i的值”(因为字符数组下标为i时第一次出现了尾零,则字符串长度就是i)。只看低八位的话,此时 - 1相当于255,所以i == 255的时候,
- 1 - i(255 - 255)的低八位全部都是0,也就是当i为255的时候,a[i]第一次为0,所以a[i]的长度就是255了。*/
for (i = 0; i < 1000; i++)
{
a[i] = -1 - i; //-128~127
}
printf("%d", strlen(a)); //strlen(a)----255
return 0;
}
パート3。電卓の大小の端
大小の終わりは何ですか
コードを使用して、現在使用しているプラットフォームがビッグエンディアンストレージを使用しているかリトルエンディアンストレージを使用しているかを確認しましょう。
#include<stdio.h>
int check_sys()
{
int i =0x00000001;
char* p = (char *)&i; //让它只能访问一个字节的内容
return *p;
}
int main()
{
if (check_sys() == 1)
{
//把一个数据的低位字节序的内容,存放在低地址处
// 高位字节的内容,存放在高位地址处
printf("小端\n"); //1在小端内存存储的十六进制----------01 00 00 00
}
else
{
//把一个数据的低位字节序的内容,存放在高位地址处
//高位字节序的内容,存放在低位地址处
printf("大端\n"); //1在大端内存存储的十六进制----------00 00 00 01
}
return 0;
}
上の図から、vs2019ストレージはリトルエンディアンストレージであることがわかります
パート4。データストレージ-浮動小数点
国際標準IEEE(Institute of Electrical and Electronic Engineering)754によると、任意の2進浮動小数点数Vは、次の形式で表すことができます。
(-1)^ S * M * 2 ^ E
(-1)^ sは符号ビット、s = 0の場合、Vは正の数、s = 1の場合、Vは負の数です。
Mは、1以上2未満の有意な数を表します。
2 ^ Eは指数ビットを表します。
例:10進数で5.0、2進数で101.0、1.01×2 ^ 2に相当します。次に、上記のVの形式に従って、s = 0、
M = 1.01、およびE = 2を取得できます。
2進数で記述された10進数の-5.0は-101.0であり、これは-1.01×2 ^ 2に相当します。次に、s = 1、M = 1.01、およびE = 2です。
IEEE 754では、次のように規定されています。32ビット浮動小数点数の場合、最上位1ビットは符号ビットs、次の8ビットは指数E、残りの23ビットは有効桁数Mです。
64ビット浮動小数点数の場合、最上位1ビットは符号ビットS、次の11ビットは指数E、残りの52ビットは有効数字Mです。
IEEE 754番号Mと実効指数E、いくつかの特別な規定。前述のように、1≤M<2、つまりMは1.xxxxxxの形式で記述できます
。ここで、xxxxxxは小数部分を表します。
IEEE 754では、Mをコンピューターに保存する場合、この番号の最初の桁はデフォルトで常に1であるため、破棄でき、次のxxxxxx部分のみが保存されると規定されています。
たとえば、1.01を保存すると、01のみが保存され、読み取られると、最初の1が追加されます。これの目的は、1つの有効数字を保存することです。
例として32ビット浮動小数点数を取り上げます。Mには23ビットしか残っていません。最初の桁の1を切り捨てると、有効数字24桁になります。
インデックスEに関しては、状況はより複雑です。
まず、Eは符号なし整数(unsigned int)です。つまり、Eが8ビットの場合、その値の範囲は0〜255です。Eが11ビットの場合、その
値の範囲は0〜2047です。ただし、科学的記数法ではEが負の数である場合、IEEE 754はリアルタイムでメモリEを提供します。実
数値の中間値は数値と組み合わせる必要があります。8ビットEの場合、中間の数値は127です。 11桁のE、中央の数字は1023です。たとえば
、2 ^ 10のEは10であるため、32ビット浮動小数点数として保存する場合は、10 + 127 = 137、つまり10001001として保存する必要があります。
次に、指数Eがメモリから取り出され、さらに3つのケースに分けることができます
。Eがすべて0ではない、またはすべて1ではない場合
、浮動小数点数は次のルールで表されます。つまり、指数Eから127(または1023)を引いた値を取得し、真の値を取得して、実効数Mの前の
最初の桁に1を加算します。例:0.5(1/2)の2進形式は0.1です。これは、正の部分が1でなければならないためです。つまり、小数点が1桁右にシフトされ、
1.0 * 2 ^(-1)になります。 、およびその順序コードは-1 + 127 = 126は01111110として表され、マンティッサ1.0は整数部分を0に削除し、
0〜23ビットを入力します00000000000000000000000、そのバイナリ表現は次のとおりです
。Eはすべて0
この時点で、浮動小数点数の指数Eが1-127(または1-1023)に等しい場合は真の値であり、実効桁Mは最初の1に追加されなくなりますが
、小数点以下0.xxxxxxに復元されます。これは、±0、およびゼロに近い非常に小さい数値を表すために行われます。この時点
でEはすべて1
です。有効数字Mがすべて0の場合、±無限大を意味します(正または負は符号ビットsによって異なります)。
int main()
{
int n = 9;
//0 00000000 00000000000000000001001 ----整数存储形式
//(-1)^0 * 0.00000000000000000001001 * 2^-126 ----单精度浮点数存储形式
float *pFloat = (float *)&n;
printf("n的值为:%d\n", n);//9
printf("*pFloat的值为:%f\n", *pFloat);//0.000000
*pFloat = 9.0;
//1001.0
//(-1)^0 * 1.001*2^3
//S=0 ----表示的是符号位 0为正 ,负数为1
//M=1.001
//E=3 +127
//9.0 -> 1001.0 ->(-1)^01.0012^3 -> s=0, M=1.001,E=3+127=130
//01000001000100000000000000000000
printf("num的值为:%d\n", n);//直接打印整形时,就是2进制到十进制转换
printf("*pFloat的值为:%f\n", *pFloat);//9.0
return 0;
}
さて、それだけです。