我是在本网站的基础上创建的,它计算主机、网络掩码等IP地址信息。
我对C非常陌生,我仍然掌握着整个数组、指针和位操作的概念。代码的工作方式,我希望它的工作,但我想改进这一点。我想知道我是如何做的,以及在用C语言编程时我可以注意的一些事情。
#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);
}
}发布于 2016-09-18 03:54:25
之前初始化
int bit\_counter, net\_bit\_counter = 0;
有几个问题。首先,如果在同一语句中声明和初始化,则只应声明一个变量。
int bit_counter = 0;
int net_bit_counter = 0;如果有两个变量,则在两行上声明它们。只有在初始化任何一个变量时,才在一行上声明多个变量。有些人甚至在那时候也不会争辩。没有功能上的区别,但是在一个单独的行上使用每个初始化的声明更容易阅读。
第二,不初始化bit_counter。C不会自动将变量初始化为默认值,因此这可能会导致奇怪的行为。当我第一次尝试运行这段代码时,它给了我一个运行时错误,直到我初始化了所有变量。
while (bit\_counter != 33) {
这有点易碎。目前,您允许bit_counter在此循环的每一次迭代中多次递增。如果当它是32,你增加到34,而没有击中这个检查?检查将一直保持成功,直到程序崩溃(可能是由于试图在数组外写入)。
while (bit_counter <= 32) {这要有力得多。它不再需要精确地击中目标才能停下来。现在它将停止任何大于32的值,而不仅仅是33。
对于可读性来说,另一个好处是,它现在表示32,这是这里的临界值。之前,它说33,这比最后一个数字多一个。
但这其实是个窃听器。它应该是
while (bit_counter < 32) {因为literal_bit_mask只有32长。第一个元素是0。最后一个元素是31。现在它不会写过数组的末尾。
递增
net\_bit\_counter += 1; bit\_counter += 1;
你可以把它写成
++net_bit_counter;
++bit_counter;这在功能上不会有太大影响(在许多平台上可能没有),但大多数C程序员会发现这一点更容易识别。
我使用前缀表单是因为一些C编译器可能不够聪明,无法避免后缀表单的复制步骤。我希望大多数编译器都会对其进行优化,但我们不需要依赖它。在这里不太可能有明显的变化。
++bit_counter递增bit_counter并返回该值。bit_counter++返回它在增量之前的值。如果您不使用该值(就像这里不使用的那样),则没有真正的功能差异。编译器可能返回不同的机器指令。特别是,它可能会将值复制到另一个寄存器,然后递增。这没有必要,如果
以下内容在功能上是等价的(让变量在结尾处有相同的值):
int var = bit_counter++;和
int var = bit_counter;
bit_counter++;和
int var = bit_counter;
++bit_counter;以下内容与前三个不同,但在功能上是相互等效的:
bit_counter++;
int var = bit_counter;和
++bit_counter;
int var = bit_counter;和
int var = ++bit_counter;如果bit_counter从0开始并增加到1,那么前三个将var设置为0。最后三个将将var设置为1。
许多人认为,如果变量在单独的行中被更改,则更容易阅读。这就清楚地表明,变量正在发生变化。在同一条线上做两件事是不太明显的,因为人们可能会看到其中一件而错过另一件。
发布于 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()的虚线四边形。
#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;
}https://codereview.stackexchange.com/questions/141674
复制相似问题