为什么在 Socket Programming - C 中将位移动 8?

Why shift bits by 8 in Socket Programming - C?

我正在学习 FreeBSH 开发人员手册,我在那里看到了这段用于套接字编程的代码:

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 和/或它。有人可以解释一下吗?

让我们先看看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() converts the Internet host address cp from the IPv4 numbers-and-dots notation into binary form (in network byte order) and stores it in the structure that inp points to. inet_aton() returns nonzero if the address is valid, zero if not.

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

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

它正在为 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

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

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