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]);
Expected output is 1st 64 bits of the address which will be 2^61 =
2305843009213693952.
But when i execute the program i am getting output as 32 which is the
first byte of the address.
我不明白背后的原因,请帮忙。谢谢!
除了注释中指出的任何问题外,使用错误的 printf()
格式说明符也是未定义的行为。
根据 7.21.6 格式化 input/output 函数,the C standard 的第 9 段:
If a conversion specification is invalid, the behavior is
undefined. If any argument is not the correct type for the
corresponding conversion specification, the behavior is
undefined.
鉴于
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]);
这甚至无法编译 - 它是一个未终止的字符串。第二个 "
字符被转义为 \"
。我假设你的意思是 "%u\n"
.
你这里有几个问题。
您打印结果的方法本身就有缺陷。 printf
指令 %u
不是一般用于打印无符号整数,而是专门用于打印类型 unsigned int
的值。尽管您的 int64_t
可能与 unsigned int
是同一类型,但那是非典型的。如果它们不是同一类型,则指令和实际参数之间的不匹配会导致未定义的行为。 @AndrewHenle 在他的回答中解释了如何通过 printf
.
打印 int64_t
通过使用 union
将 struct in6_addr
的字节映射到 int64_t
的数组上,您将自己暴露在字节顺序的细节中您的实现对 int64_t
的表示。您完全可以呈现特定的预期结果表明您假设了一种特定的表示形式(显然与您的系统不匹配)。
您似乎认为打印的字节数少于应有的字节数,但即使您根据 Andrew 的回答更正了 printf
格式,我倾向于认为输出将是相同。您观察到打印的值对应于地址的第一个字节,但请考虑接下来的几个字节是什么:全为零,直到到达最后两个字节。现在考虑一个位模式,它由一个值为 32(十进制)的字节组成,后面跟着七个值为零的字节。如果将该模式解释为 64 位无符号小端整数,则其值为 32。这是最有可能在基于 Intel 的机器上打印更正代码的值。
显然您想生成 int64_t
个值,其 逻辑 位模式与地址位匹配。相反,您生成的值的 physical 位模式与地址位匹配。当您使用 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。
我正在尝试将字符串格式的 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]);
Expected output is 1st 64 bits of the address which will be 2^61 = 2305843009213693952.
But when i execute the program i am getting output as 32 which is the first byte of the address.
我不明白背后的原因,请帮忙。谢谢!
除了注释中指出的任何问题外,使用错误的 printf()
格式说明符也是未定义的行为。
根据 7.21.6 格式化 input/output 函数,the C standard 的第 9 段:
If a conversion specification is invalid, the behavior is undefined. If any argument is not the correct type for the corresponding conversion specification, the behavior is undefined.
鉴于
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]);
这甚至无法编译 - 它是一个未终止的字符串。第二个 "
字符被转义为 \"
。我假设你的意思是 "%u\n"
.
你这里有几个问题。
您打印结果的方法本身就有缺陷。
printf
指令%u
不是一般用于打印无符号整数,而是专门用于打印类型unsigned int
的值。尽管您的int64_t
可能与unsigned int
是同一类型,但那是非典型的。如果它们不是同一类型,则指令和实际参数之间的不匹配会导致未定义的行为。 @AndrewHenle 在他的回答中解释了如何通过printf
. 打印 通过使用
union
将struct in6_addr
的字节映射到int64_t
的数组上,您将自己暴露在字节顺序的细节中您的实现对int64_t
的表示。您完全可以呈现特定的预期结果表明您假设了一种特定的表示形式(显然与您的系统不匹配)。您似乎认为打印的字节数少于应有的字节数,但即使您根据 Andrew 的回答更正了
printf
格式,我倾向于认为输出将是相同。您观察到打印的值对应于地址的第一个字节,但请考虑接下来的几个字节是什么:全为零,直到到达最后两个字节。现在考虑一个位模式,它由一个值为 32(十进制)的字节组成,后面跟着七个值为零的字节。如果将该模式解释为 64 位无符号小端整数,则其值为 32。这是最有可能在基于 Intel 的机器上打印更正代码的值。
int64_t
显然您想生成 int64_t
个值,其 逻辑 位模式与地址位匹配。相反,您生成的值的 physical 位模式与地址位匹配。当您使用 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。