【问题标题】:Converting an uint8_t[] to an IP address string [duplicate]将 uint8_t[] 转换为 IP 地址字符串 [重复]
【发布时间】:2019-05-13 21:59:32
【问题描述】:

我目前正在学习 C。我的生态系统由 Espressif ESP-32 微控制器和 Eclipse CDT IDE 组成。

我正在尝试将uint8_t[] 转换为人类可读的IPv4 address string。到目前为止,我想出了以下代码:

void app_main() {
    uint8_t[] ip = {192, 168, 0, 99};
    dump_ip(ip);
}

void dump_ip(const uint8_t *in) {
    // ip addresses consist of three dots + terminator '\0'
    int size = 4;
    // count amount of chars needed for specific ip address
    for(int i=0; i<4; i++) {
        if(in[i]==0) {
            size ++;
        } else {
            size += ((int)log10(in[i]))+1;
        }
    }
    // allocate memory on heap for an ip address of length 'size'
    char *ip_str = (char*)malloc(size*sizeof(char));
    // copy ip address parts to char array
    int pos = 0;
    for(int i=0; i<4; i++) {
        if(in[i]==0) {
            ip_str[pos] = '0';
            pos++;
        } else {
            char b[4];
            itoa(in[i], b, 10);
            for(int j=0; j<3; j++) {
                if(b[j]!='0') {
                    ip_str[pos] = b[j];
                    pos++;
                }
            }
        }
        // add dot between ip address parts
        if(i<3) {
            ip_str[pos] = '.';
            pos++;
        }
    }
    // add terminator at end of string
    ip_str[pos] = '\0';
    // print to uart interface
    uart_send(ip_str);
    // release allocated heap memory
    free(ip_str);
}

在使用不同的 IP 阵列进行测试时,我得到以下结果:

uint8_t[] ip = {192, 168, 0, 99};   =>   "192.168.0.99"   => OK
uint8_t[] ip = {192, 168, 1, 99};   =>   "192.168.1"      => FAILED
uint8_t[] ip = {192, 168, 10, 99};  =>   "192.168.1"      => FAILED
uint8_t[] ip = {10, 10, 10, 10};    =>   "1"              => FAILED
// etc. etc. etc. 

我做错了什么?有没有更优雅的方法来实现这一点?

【问题讨论】:

  • 如何使用inet_ntoa
  • 为什么不保留一个固定大小的缓冲区而不是所有复杂的逻辑。一个ipv4地址最长可以是16(999.999.999.999\0)

标签: c ip-address


【解决方案1】:

snprintf吧。

void app_main() {
    uint8_t ip[] = {192, 168, 0, 99};
    char buf[3 * 4 + 3 * 1 + 1];
    snprintf(buf, sizeof(buf), "%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]);
    uart_send(buf);
}

uint8_t[] ip 无效 C,[] 在变量名之后。

  1. sprintfsnprintf 会将格式化后的字符串打印到第一个 arg 指向的内存中。
  2. snprintf 将额外的最大大小参数作为第二个参数。
  3. uint8_t 变量在传入变量参数列表时会自动转换为 int - 因此您可以使用 %d printf 修饰符打印它们。
  4. 那么你就有了人类可编辑的、以空结尾的字符串。

【讨论】:

  • 太好了,一行 :-) 谢谢!
【解决方案2】:

最好的答案就是按照 Kamil Cuk 的建议使用 snprintf

但是,如果您仍然想知道为什么您的代码不起作用,答案就在这一行:

if(b[j]!='0') {

您只是在复制不为零的字符,其中包括空字符。因此,当 IP 的一段包含少于 3 个字符时,您会将空值复制到字符串中。修复很简单:

if(b[j]!='\0') {

这让我觉得这很可能只是一个错字!

【讨论】:

  • 感谢您的解释!
猜你喜欢
  • 1970-01-01
  • 2020-10-22
  • 1970-01-01
  • 2020-05-06
  • 1970-01-01
  • 2021-10-15
  • 1970-01-01
  • 1970-01-01
  • 2023-03-05
相关资源
最近更新 更多