首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >计算IP地址

计算IP地址
EN

Code Review用户
提问于 2016-09-18 01:58:08
回答 2查看 1.9K关注 0票数 6

我是在本网站的基础上创建的,它计算主机、网络掩码等IP地址信息。

我对C非常陌生,我仍然掌握着整个数组、指针和位操作的概念。代码的工作方式,我希望它的工作,但我想改进这一点。我想知道我是如何做的,以及在用C语言编程时我可以注意的一些事情。

代码语言:javascript
复制
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>

#define B1 0
#define B2 1
#define B3 2
#define B4 3
#define CIDR 4

void ConvertIpToInt(char address[], int address_block[]);

int main(int argc, char** argv) {

    int address_block[4], netmask_block[4];

    char address[] = "128.42.0.0/25";

    ConvertIpToInt(address, address_block);

    char literal_netmask_bin[32];
    int bit_counter, net_bit_counter = 0;
    while (bit_counter != 33) {
        while (net_bit_counter != address_block[CIDR]) {
            literal_netmask_bin[bit_counter] = '1';
            net_bit_counter += 1;
            bit_counter += 1;
        }
        literal_netmask_bin[bit_counter] = '0';
        bit_counter += 1;
    }

    int i, block_counter, sqN_value, sqN = 0;
    bit_counter = 0;
    for (i = 0; i < 33; i++) {
        bit_counter += 1;
        if (literal_netmask_bin[i] == '1') {
            sqN_value += pow(2, 7 - sqN);
        }
        sqN += 1;
        if (bit_counter == 8) {
            netmask_block[block_counter] = sqN_value;
            bit_counter = 0;
            sqN = 0;
            sqN_value = 0;
            block_counter += 1;
        }
    }

    int wildcard_netmask_block[4];
    i = 0;
    for (i = 0; i < 4; i++) {
        wildcard_netmask_block[i] = ~netmask_block[i] & 0xFF;
    }

    printf("> [GENERAL]\n\n");
    printf("Address:---------------------> %d.%d.%d.%d\n", address_block[B1], address_block[B2], address_block[B3], address_block[B4]);
    printf("Network Mask:----------------> %d.%d.%d.%d => %d\n", netmask_block[B1], netmask_block[B2], netmask_block[B3], netmask_block[B4], address_block[CIDR]);
    printf("Wildcard Mask:---------------> %d.%d.%d.%d\n", wildcard_netmask_block[B1], wildcard_netmask_block[B2], wildcard_netmask_block[B3], wildcard_netmask_block[B4]);
    printf("Network Address:-------------> %d.%d.%d.%d\n", address_block[B1] & netmask_block[B1], address_block[B2] & netmask_block[B2], address_block[B3] & netmask_block[B3], address_block[B4] & netmask_block[B4]);
    printf("Broadcast Address:-----------> %d.%d.%d.%d\n", wildcard_netmask_block[B1] | address_block[B1], wildcard_netmask_block[B2] | address_block[B2], wildcard_netmask_block[B3] | address_block[B3], wildcard_netmask_block[B4] | address_block[B4]);
    printf("Minimum Usable Address:------> %d.%d.%d.%d\n", address_block[B1] & netmask_block[B1], address_block[B2] & netmask_block[B2], address_block[B3] & netmask_block[B3], (address_block[B4] & netmask_block[B4]) + 1);
    printf("Maximum Usable Address:------> %d.%d.%d.%d\n", wildcard_netmask_block[B1] | address_block[B1], wildcard_netmask_block[B2] | address_block[B2], wildcard_netmask_block[B3] | address_block[B3], (wildcard_netmask_block[B4] | address_block[B4]) - 1);
    printf("Number of Hosts:-------------> %d\n", (int) pow(2, 32 - address_block[CIDR]) - 2);
    printf("Total Hosts:-----------------> %d\n\n", (int) pow(2, 32 - address_block[CIDR]));
}

void ConvertIpToInt(char address[], int address_block[]) {
    char * pch;
    char delimeters[] = "./";
    pch = strtok(address, delimeters);
    int i = 0;
    while (pch != NULL) {
        address_block[i] = strtol(pch, NULL, 10);
        i += 1;
        pch = strtok(NULL, delimeters);
    }
}
EN

回答 2

Code Review用户

回答已采纳

发布于 2016-09-18 03:54:25

在使用

之前初始化

int bit\_counter, net\_bit\_counter = 0;

有几个问题。首先,如果在同一语句中声明和初始化,则只应声明一个变量。

代码语言:javascript
复制
    int bit_counter = 0;
    int net_bit_counter = 0;

如果有两个变量,则在两行上声明它们。只有在初始化任何一个变量时,才在一行上声明多个变量。有些人甚至在那时候也不会争辩。没有功能上的区别,但是在一个单独的行上使用每个初始化的声明更容易阅读。

第二,不初始化bit_counter。C不会自动将变量初始化为默认值,因此这可能会导致奇怪的行为。当我第一次尝试运行这段代码时,它给了我一个运行时错误,直到我初始化了所有变量。

知道你的界限

while (bit\_counter != 33) {

这有点易碎。目前,您允许bit_counter在此循环的每一次迭代中多次递增。如果当它是32,你增加到34,而没有击中这个检查?检查将一直保持成功,直到程序崩溃(可能是由于试图在数组外写入)。

代码语言:javascript
复制
    while (bit_counter <= 32) {

这要有力得多。它不再需要精确地击中目标才能停下来。现在它将停止任何大于32的值,而不仅仅是33。

对于可读性来说,另一个好处是,它现在表示32,这是这里的临界值。之前,它说33,这比最后一个数字多一个。

但这其实是个窃听器。它应该是

代码语言:javascript
复制
    while (bit_counter < 32) {

因为literal_bit_mask只有32长。第一个元素是0。最后一个元素是31。现在它不会写过数组的末尾。

C由一个运算符

递增

net\_bit\_counter += 1; bit\_counter += 1;

你可以把它写成

代码语言:javascript
复制
            ++net_bit_counter;
            ++bit_counter;

这在功能上不会有太大影响(在许多平台上可能没有),但大多数C程序员会发现这一点更容易识别。

我使用前缀表单是因为一些C编译器可能不够聪明,无法避免后缀表单的复制步骤。我希望大多数编译器都会对其进行优化,但我们不需要依赖它。在这里不太可能有明显的变化。

++bit_counter递增bit_counter并返回该值。bit_counter++返回它在增量之前的值。如果您不使用该值(就像这里不使用的那样),则没有真正的功能差异。编译器可能返回不同的机器指令。特别是,它可能会将值复制到另一个寄存器,然后递增。这没有必要,如果

以下内容在功能上是等价的(让变量在结尾处有相同的值):

代码语言:javascript
复制
int var = bit_counter++;

代码语言:javascript
复制
int var = bit_counter;
bit_counter++;

代码语言:javascript
复制
int var = bit_counter;
++bit_counter;

以下内容与前三个不同,但在功能上是相互等效的:

代码语言:javascript
复制
bit_counter++;
int var = bit_counter;

代码语言:javascript
复制
++bit_counter;
int var = bit_counter;

代码语言:javascript
复制
int var = ++bit_counter;

如果bit_counter从0开始并增加到1,那么前三个将var设置为0。最后三个将将var设置为1。

许多人认为,如果变量在单独的行中被更改,则更容易阅读。这就清楚地表明,变量正在发生变化。在同一条线上做两件事是不太明显的,因为人们可能会看到其中一件而错过另一件。

票数 3
EN

Code Review用户

发布于 2016-09-19 19:24:45

重新发明车轮

解析CIDR表示法是一项比较常见的任务,您就是重新发明车轮。事实上,有一个inet_net_pton(3)函数正是这样做的,它可以在BSD (包括macOS)、Linux和其他Unix口味中使用。

inet_net_pton()函数将表示格式Internet (即字符串中可打印的表单)转换为网络格式(通常是struct in_addr或其他一些内部二进制表示,按网络字节顺序排列)。它返回位数,或者根据类计算,或者用/CIDR指定),或者-1如果发生故障(在这种情况下将设置errno )。如果因特网网络号码无效,它将被设置为ENOENT )。

Windows没有inet_net_pton()函数,但它支持解析地址而不是网络掩码的inet_pton()POSIX函数

即使你想为了好玩或出于必要而重新发明轮子,看看它是如何按照惯例完成也是值得的,因为:

  • 您可以从其他程序员的设计决策中吸取教训。
  • 如果您的代码遵循传统的方法,其他程序员可能更容易理解它。
  • 按照标准接口,您可以创建可互操作的代码。

特别是,通过使用struct in_addr来表示IPv4地址,您可以在真正建立网络连接的代码中实际使用解析的结果。( struct in_addr只包含大端格式的32位无符号整数。)

下面是一个基于inet_net_pton()的解决方案。我想你会同意这更简单。请注意,每个计算同时在整个地址上工作,并且每个结果都很容易被格式化为使用inet_ntop()的虚线四边形。

代码语言:javascript
复制
#include <inttypes.h>
#include <stdio.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/types.h>

/**
 * Parses a string in CIDR notation as an IPv4 address and netmask.
 * Returns the number of bits in the netmask if the string is valid.
 * Returns -1 if the string is invalid.
 */
int parse_cidr(const char *cidr, struct in_addr *addr, struct in_addr *mask) {
    int bits = inet_net_pton(AF_INET, cidr, addr, sizeof addr);
    /* Shifting by 32 bits is undefined (http://stackoverflow.com/q/2648764) */
    mask->s_addr = htonl(~(bits == 32 ? 0 : ~0U >> bits));
    return bits; 
}   

/**
 * Formats the IPv4 address in dotted quad notation, using a static buffer.
 */
const char *dotted_quad(const struct in_addr *addr) {
    static char buf[INET_ADDRSTRLEN];
    return inet_ntop(AF_INET, addr, buf, sizeof buf);
}   

int main(int argc, char *argv[]) {
    struct in_addr addr, mask, wildcard, network, broadcast, min, max;
    int64_t num_hosts;

    int bits = parse_cidr(argv[1], &addr, &mask);
    if (bits == -1) {
        fprintf(stderr, "Invalid address/netmask: %s\n", argv[1]));
        return 1;
    }

    wildcard = mask;    wildcard.s_addr = ~wildcard.s_addr;
    network = addr;     network.s_addr &= mask.s_addr;
    broadcast = addr;   broadcast.s_addr |= wildcard.s_addr;
    min = network;      min.s_addr = htonl(ntohl(min.s_addr) + 1);
    max = broadcast;    max.s_addr = htonl(ntohl(max.s_addr) - 1);
    num_hosts = (int64_t)ntohl(broadcast.s_addr) - ntohl(network.s_addr) + 1;

    printf("> [GENERAL]\n\n");
    printf("Address:---------------------> %s\n", dotted_quad(&addr));
    printf("Network Mask:----------------> %s => %d\n", dotted_quad(&mask), bits);
    printf("Wildcard Mask:---------------> %s\n", dotted_quad(&wildcard));
    printf("Network Address:-------------> %s\n", dotted_quad(&network));
    printf("Broadcast Address:-----------> %s\n", dotted_quad(&broadcast));
    if (num_hosts > 2) {
        printf("Minimum Usable Address:------> %s\n", dotted_quad(&min));
        printf("Maximum Usable Address:------> %s\n", dotted_quad(&max));
        printf("Number of Hosts:-------------> %" PRId64 "\n", num_hosts - 2);
    }   
    printf("Total Hosts: ----------------> %" PRId64 "\n", num_hosts);
    return 0;
}
票数 2
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/141674

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档