歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux編程 >> Linux編程 >> C語言中的整數在內存中的格式

C語言中的整數在內存中的格式

日期:2017/3/1 10:11:53   编辑:Linux編程

big endian 和 small endian

在intel機器上都是采用的small endian即小端字節序,也就是地位的地址低,高位的地址高。

  1. int i = 0x12345678
  2. char c1 = *(char*)(&i)

一個int型整數的地址就是其最低位的地址,所以上例中c1的值就是0x78
那麼整數的正數,負數,以及無符號整數的表示方法有什麼區別呢
對於正整數來說,內存裡裝的就是它自己的二進制碼

  1. 0x12345678 = > 0001 0010 0011 0100 0101 0110 0111 1000
  2. 求反 1110 1101 1100 1011 1010 1001 1000 0111
  3. +1 1110 1101 1100 1011 1010 1001 1000 1000
  4. 結果 0xedcba988

而負數呢,是對齊相應的整數,逐位求反,然後+1.

負數的最高位都是1,不是規定的,而是算出來的結果,最高位必為1.
根據上述算法-1 不是0x80000001 而是0xFFFFFFFF.

下面相應的介紹一下左移<<和右移>>的計算.
左移:

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. int main(){
  4. int a = 0x80000001;
  5. int b = 0x70000000;
  6. int c = 1;
  7. printf("a:%x(%d)\n", a<<1, a<<1);
  8. printf("b:%x(%d)\n", b<<1, b<<1);
  9. return 1;
  10. }
  11. a:80000000(-2147483648)
  12. b:2(2)

左移相對比較簡單,是不考慮符號位的,符號位也會被移除,正數可能左移成負數,負數也可能編程正數

而右移呢,就需要考慮符號位了。右移過程中符號位保持不變,但注意符號位如果是1也是右移給右側一位的,雖然自己不變。

  1. int main(){
  2. int b = 0x80000001;
  3. printf("b:%x\n", b>>1);
  4. return 1;
  5. }
  6. [zhouqz@fb119 ~]$ ./a.out
  7. b:c0000000

上例的結果既不是0x40000000也不是0x00000000,居然是0xc0000000(1100 0000 0000 ....)

那麼無符號有什麼區別麼?左移來說,沒有任何區別,但對於右移來說,因為無符號整數表示最高位不是符號位,右移就可以移動了
所以0x80000000 >> 1 就是0x40000000了

利用上面的特點,我們可以很技巧的判斷一個給定的子網掩碼是不是合法的掩碼,什麼是合法的呢?就是從左開始一直是1,一旦遇到0後,後續的不能再有1的出現。

  1. int is_netmask_valid(int mask){
  2. if(((mask >> 1) & mask) == mask){
  3. return 1;
  4. }
  5. return 0;
  6. }

注意參數必須是int不能是unsigned int,因為要利用右移保留符號位的特性。
道理比較簡單,就是子網掩碼一定是1...10...0的格式,右移之後,1的個數會多一個,但是和原來的mask做&操作後還是mask,如果mask是非法的,0與0之間一定混有1,一旦 右移又與操作後,就會多出2個1,就會不等於原來的mask了

怎麼求一個合法的掩碼的位數呢?

  1. int get_bit_of_netmask(int mask){
  2. int i = 0;
  3. while(mask){
  4. mask = mask << 1;
  5. i++;
  6. }
  7. return i;
  8. }
Copyright © Linux教程網 All Rights Reserved