【问题标题】:Why shift bits by 8 in Socket Programming - C?为什么在套接字编程 - C 中移位 8 位?
【发布时间】:2015-07-07 07:09:15
【问题描述】:

我正在研究 FreeBSH 开发人员手册,并且在那里我看到了用于 Socket 编程的代码:

struct sockaddr_in sa;
sa.sin_addr.s_addr = htonl((((((192 << 8) | 43) << 8) | 244) << 8) | 18);

为什么在这里使用按位移位和或?

我知道什么是移位和异或,我做了一个非常小的测试程序:

int c = 5;
printb(c);

int d = 5<<2;
printb(d);

int e = d | c;
printb(e);

哪个打印:

00000000000000000000000000000101
00000000000000000000000000010100
00000000000000000000000000010101

但是我不明白为什么对于 sa.sin_addr.s_addr 我需要使用以下值移动 ip 和/或它。谁能解释一下?

【问题讨论】:

  • 它通过使用十进制数 18 作为最低 8 位,244 作为高 8 位,为 htonl 创建一个 32 位参数(从 9 到 16),43 作为高 8 位(从 17 到 24),192 作为高 8 位(从 25 到 32)
  • @mescalinum 是的,但是如何?为什么要异或?为什么要转移?
  • Sockets Essential 可以帮忙。
  • @KorayTugay,你的例子中没有xor (^),你的意思是or (|)
  • @AlterMann 是 |或者..

标签: c sockets ip bit-manipulation


【解决方案1】:

它正在为 IP 192.43.244.18 创建二进制表示。

让我们一一分析每个操作。

从这些常量的二进制表示开始:

192 = 11000000
 43 = 00101011
244 = 11110100
 18 = 00010010

最里面的操作:

(192 << 8) =

= 11000000 << 8 =

= 1100000000000000

下一个:

(192 << 8) | 43 =

= 1100000000000000 |
          00101011 =

  1100000000101011

下一个:

((192 << 8) | 43) << 8) =

= 1100000000101011 << 8 =

= 110000000010101100000000

下一个:

(((192 << 8) | 43) << 8) | 244 =

= 110000000010101100000000 | 244 =

= 110000000010101100000000 |
                  11110100 =

= 110000000010101111110100

下一个:

(((192 << 8) | 43) << 8) | 244) << 8 =

= 110000000010101111110100 << 8 =

= 11000000001010111111010000000000

最后:

(((((192 << 8) | 43) << 8) | 244) << 8) | 18 =

= 11000000001010111111010000000000 | 18 =

= 11000000001010111111010000000000 |
                          00010010 =

= 11000000001010111111010000010010

【讨论】:

  • 啊,我现在明白了.. 谢谢。我不知道leftshift加了0所以我听不懂..
  • 加 1 - 回答得很好。
  • @KorayTugay 是的,即使我将这些常量写为 8 位,它们也是 32 位整数表达式的一部分,因此您可以想象它们前导零 :-)
  • @mescalinum 啊,我明白了.. 感谢您的澄清。
  • 最终二进制的十进制值为:3224106002。这怎么等于192.43.244.18?
【解决方案2】:

我们先来看sock_addr_in的实际结构:

#include <netinet/in.h>

struct sockaddr_in {
    short            sin_family;   
    unsigned short   sin_port;    
    struct in_addr   sin_addr;     
    char             sin_zero[8];  
};

还有in_addr的结构体:

struct in_addr {
    unsigned long s_addr; 
};

现在,通常,当我们使用这个 s_addr 时,我们会写:

inet_aton("89.161.169.137", &myaddr.sin_addr.s_addr); //dummy ip

好的。我们检查一下 inet_aton 人怎么样?

inet_aton() 将 Internet 主机地址 cp 从 IPv4 numbers-and-dots notation into binary form (按网络字节顺序)和 将其存储在 inp 指向的结构中。 inet_aton() 返回 如果地址有效则非零,否则为零。

现在我们清楚地知道unsigned long s_addr包含网络字节顺序的二进制形式的ip。

您不需要改变 ip youreslf,只需使用 inet_aton() 和 inet_ntoa() 来操作 ip 地址。

【讨论】:

    【解决方案3】:

    首先,让我们从二元运算开始。 您正确假设的移位 'a ' 将 a 中的位向左移动 b 量。移位 1 可以看作是乘以 2。(这实际上就是优化发生的方式,因为移位操作比乘法更快,但大多数现代编译器都考虑到了这一点。) or 语句是 'a|b'。在或中,如果两个元素之一为 1,则结果为 1。这是按位运算使用的标准方法,实际上 ab 中的所有位都是或编辑。例如。 a = 0010 1011,b = 1111 0000,a|b = 1111 1011。

    现在回到问题。在您的情况下, sa.sin_addr.s_addr 开头为 0,因此当它与 192 进行或运算时,它将 192 的位表示添加到变量中。然后将其移动 8 位,以便为 ip 地址中的下一个元素腾出空间——每个元素的值都可以在 0-255 之间,正好是 8 位。然后对其余的段重复此操作。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-05-06
      • 1970-01-01
      • 1970-01-01
      • 2013-07-24
      • 2012-11-26
      • 1970-01-01
      • 2021-02-09
      • 2013-01-24
      相关资源
      最近更新 更多