繁体   English   中英

uint64_t数组的IPV6地址未按预期工作

[英]IPV6 address to array of uint64_t is not working as expected

我正在尝试将字符串格式的IPv6地址转换为uint64_t数据数组。 为此,我写了下面的程序

typedef struct
    {
        union
        {struct in6_addr  sa;
        uint64_t addr[2];
        }u;
    } ipv6_addr_t;

    ipv6_addr_t  rnc;
    char rncs[100] = "2000::200a";
    inet_pton(AF_INET6, rncs, &(rnc.u.sa));
    printf("%u\", rnc.u.addr[0]);

预期的输出是地址的第1 64位,即2 ^ 61 = 2305843009213693952。

但是,当我执行程序时,我得到的输出为32 ,这是地址的第一个字节。

我不了解其背后的原因,请帮助。 谢谢!

您在这里遇到几个问题。

  • 您打印结果的方法固有地存在缺陷。 printf指令%u并非通常用于打印无符号整数,而是专门用于打印unsigned int类型的值。 尽管您的int64_t可能与unsigned int类型相同,但这是不典型的。 如果它们不是同一类型,则伪指令和实际参数之间的不匹配将导致未定义的行为。 @AndrewHenle在他的答案中说明了如何通过printf打印int64_t

  • 通过使用并unionstruct in6_addr的字节struct in6_addrint64_t数组,您将自己暴露给实现int64_t表示形式的字节顺序。 完全可以提供特定的预期结果表明您正在假设一种特定的表示形式(显然是与您的系统不匹配的表示形式)。

  • 您似乎认为打印的字节数少于应有的字节数,但是即使您按照安德鲁的回答更正了printf格式,我也倾向于认为输出将是相同的。 您观察到打印的值与地址的第一个字节相对应,但请考虑接下来的几个字节是什么:全零,直到到达最后两个。 现在考虑一种位模式,该模式由一个值为32(十进制)的字节,然后是值为零的七个字节组成。 如果您将该模式解释为64位无符号小尾数整数,则其值为32。这是更正后的代码最有可能在基于Intel的计算机上打印的东西。

显然,您要生成其逻辑位模式与地址位匹配的int64_t值。 相反,您生成的值的物理位模式与地址位匹配。 当您使用union而不是算术在字节数组和整数之间进行转换时,这是可以预期的。 我建议改用循环:

struct in6_addr sa;
int64_t addr_ints[2] = { 0, 0 };
char rncs[100] = "2000::200a";
inet_pton(AF_INET6, rncs, &sa);

for (int i = 0; i < 16; i++) {
    addr_ints[i / 8] = addr_ints[i / 8] << 8 + sa.s6_addr[i];
}
printf( "%" PRIu64 "\n", addr_ints[ 0 ] );

如果struct in6_addr的布局与您预期的布局不同,那么这也可以避免出现问题,只要布局符合POSIX。

除了注释中指出的任何问题外,使用错误的printf()格式说明符也是未定义的行为。

根据7.21.6格式化的输入/输出功能C标准的第9段:

如果转换规范无效,则行为未定义。 如果任何参数都不是相应转换规范的正确类型,则行为未定义。

鉴于

rnc.u.addr[0]

uint64_t ,其中的printf()格式说明符%u

printf("%u\n", rnc.u.addr[0]);

是不正确的。

uint64_t的正确格式为PRIu64

printf( "%" PRIu64 "\n", rnc.u.addr[ 0 ] );

另请注意,您发布的代码不正确:

printf("%u\", rnc.u.addr[0]);

甚至不会编译-这是一个未终止的字符串。 第二个" char被转义为\\" 我认为您的意思是"%u\\n"

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM