C言語演算子、プラスチックプロモーション、切り捨て、およびプラスチック浮動小数点ストレージ

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つの右シフト操作があります。

  1. 論理シフトは左側が0で埋められ、右側が破棄されます
  2. 算術シフトの左側は元の値の符号ビットで埋められ、右側は破棄されます

ここに画像の説明を挿入
ここに画像の説明を挿入
(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;
}

さて、それだけです。

おすすめ

転載: blog.csdn.net/weixin_47812603/article/details/113530893