源碼補碼反碼
int main(int argc, const char * argv[])
{
// int占4個字節(jié) 1個字節(jié)8位
int num = 12;
/*
// 12的二進制
12在內(nèi)存中存儲的是它的補碼
00000000 00000000 00000000 00001100
正數(shù)的特點:(三碼合一) 正數(shù)的原碼就是TA的反碼就是TA的補碼
-12
二進制的最高位我們稱之為符號位
如果符號位是0代表是一個正數(shù),
如果符號位是1代表是一個負數(shù)
10000000 00000000 00000000 00001100 (-12的原碼)
11111111 11111111 11111111 11110011(反碼, 符號位不變其它位取反)
11111111 11111111 11111111 11110011
+00000000 00000000 00000000 00000001
_____________________________________________
11111111 11111111 11111111 11110100(補碼 , 反碼+1)
結論:無論正數(shù)負數(shù)在內(nèi)存中存儲的都是補碼
11111111 11111111 11111111 11110101 (補碼)
-00000000 00000000 00000000 00000001 (-1)
_____________________________________________
11111111 11111111 11111111 11110100 (反碼)
10000000 00000000 00000000 00001011
*/
printf("%d\n", 0b11111111111111111111111111110101);
return 0;
}
位運算
/*
位運算都是針對二進制的
&
|
^
~
<<
>>
*/
int main(int argc, const char * argv[])
{
/*
& 按位與
特點:只有對應的兩位都是1才返回1 否則返回0
口訣: 一假則假
規(guī)律:任何數(shù)按位與上1結果還是那個數(shù)
1001
& 0101
_______
0001
1001
&1111
______
1001
*/
/*
| 按位或
特點:只要對應的兩位其中一位是1就返回1
口訣:一真則真
1001
| 0101
________
1101
*/
/*
^ 按位異或
特點:對應的兩位不相同返回1 相同返回0
1001
^ 0101
_______
1100
// 多個整數(shù)按位異或的結果和順序無關
1001
^ 0101
_______
1100
1100
^ 0110
_______
1010
1001
^ 0110
_______
1111
1111
^ 0101
_______
1010
// 相同整數(shù)按位異或結果是0
1001
^ 1001
_______
0000
// 任何整數(shù)按位異或上0結果不變
1001
^ 0000
_______
1001
// 任何整數(shù)按位異或上另一個整數(shù)兩次結果還是那個數(shù)
1001
^ 1001
____________
0000
0000
^0101
______
0101
*/
// int result = 9 & 5;
// int result = 9 | 5;
// int result = 9 ^ 5;
// 多個整數(shù)按位異或的結果和順序無關
// int result2 = 9 ^ 5 ^ 6;
// int result2 = 9 ^ 6 ^ 5;
// 相同整數(shù)按位異或結果是0
// int result3 = 9 ^ 9;
// 任何整數(shù)按位異或上0結果不變
// int result4 = 9 ^ 0 ;
// 任何整數(shù)按位異或上另一個整數(shù)兩次結果還是那個數(shù)
// int result5 = 9 ^ 9 ^ 5;
// int result6 = 9 ^ 5 ^ 9;
// printf("result = %d\n", result6);
/*
~ 按位取反
特點: 0變1 1變0
0000 0000 0000 0000 0000 0000 0000 1001
~1111 1111 1111 1111 1111 1111 1111 0110 (補碼)
0000 0000 0000 0000 0000 0000 0000 0001
______________________________________________
1111 1111 1111 1111 1111 1111 1111 0101 (反碼)
1000 0000 0000 0000 0000 0000 0000 1010
*/
// int result = ~9;
//// printf("result = %d\n", result);
// printf("%d\n",0b11111111111111111111111111110110);
return 0;
}
左移右移
int main(int argc, const char * argv[]) {
/*
<< 左移
a << n 把整數(shù)a的二進制位往左邊移n位
移出的位砍掉,低位補0, 發(fā)現(xiàn)左移會把原有的數(shù)值變大
9 << 1 = 18 9 * 2(1) = 18
9 << 2 = 36 9 * 2(2) = 26
9 << n = 9 * 2(n)
左移的應用場景:當要計算某個數(shù)乘以2的n次方的時候就用左移,效率最高
0000 0000 0000 0000 0000 0000 0000 0000
100 0000 0000 0000 0000 0000 0000 10010
注意點:左移有可能改變數(shù)值的正負性
*/
/*
>> 右移
a >> n 把整數(shù)a的二進制位往右邊移n位
移出的位砍掉, 缺少的以為最高位是0就補0是1就補1(是在當前操作系統(tǒng)下)
9 >> 1 = 4 9 / 2(1) = 4
9 >> 2 = 2 9 / 2(2) = 2
右移的應用場景:當要計算某個數(shù)除以2的N次方的時候就用右移,效率最高
0000 0000 0000 0000 0000 0000 0000 0000
000000 0000 0000 0000 0000 0000 0000 10
*/
// int result = 9 << 2;
int result = 9 >> 2;
printf("result = %d\n", result);
return 0;
}
變量存儲細節(jié)
int main(int argc, const char * argv[]) {
// 變量為什么要有類型? 每種類型占用的內(nèi)存空間不一樣 int 4, char 1 double 8
// 只要定義變量, 系統(tǒng)就會開辟一塊存儲空間給我們的變量存儲數(shù)據(jù), 內(nèi)存尋址是從大到小
// 越先定義的變量, 內(nèi)存地址越大
// 變量的地址就是所占的存儲空間最小的字節(jié)地址
int num;
// 注意: 由于內(nèi)存尋址是從大到小, 所以存儲數(shù)據(jù)也是從大到小的存儲(先存儲二進制的高位, 再存儲低位)
// 高位 --> 低位
// 00000000 00000000 00000000 00001001
num = 9; // 9 -->二進制 -->存儲(補碼)
int value;
value = 600; //00000000 00000000 00000010 01011000
// %p是輸出地址
// &變量名稱, 是取出變量的地址
printf("num = %p\n", &num);
printf("value = %p\n", &value);
// 獲取存儲的每一位
char *c = &value;
for (int i = 0; i < sizeof(num); i++) {
int result = c[i]; // 取出每個字節(jié)中存儲的數(shù)據(jù)
printf("%i\n", result);
}
return 0;
}