如何在C语言中将结构转换为字符数组
我正在尝试将结构转换为字符数组,以便通过网络发送。然而,当我这样做时,我从char数组中得到了一些奇怪的输出如何在C语言中将结构转换为字符数组,c,pointers,struct,char,C,Pointers,Struct,Char,我正在尝试将结构转换为字符数组,以便通过网络发送。然而,当我这样做时,我从char数组中得到了一些奇怪的输出 #include <stdio.h> struct x { int x; } __attribute__((packed)); int main() { struct x a; a.x=127; char *b = (char *)&a; int i; for (i=0; i<4; i++) printf("
#include <stdio.h>
struct x
{
int x;
} __attribute__((packed));
int main()
{
struct x a;
a.x=127;
char *b = (char *)&a;
int i;
for (i=0; i<4; i++)
printf("%02x ", b[i]);
printf("\n");
for (i=0; i<4; i++)
printf("%d ", b[i]);
printf("\n");
return 0;
}
#包括
结构x
{
int x;
}_uuu属性_uuu((压缩));
int main()
{
结构xa;
a、 x=127;
字符*b=(字符*)&a;
int i;
对于(i=0;ichar是一种有符号类型;因此对于2的补码,0x80是-128,表示8位整数(即一个字节)char是一种有符号类型,因此您看到的是两个互补表示,强制转换为(unsigned char*)将解决这个问题(Rowland刚刚击败了我)
在旁注上,您可能需要更改
for (i=0; i<4; i++) {
//...
}
<代码> >(i=0;i您可能想转换为一个无符号字符数组。将结构视为字符数组是未定义行为。要通过网络发送它,使用适当的序列化。这是C++中的一种痛苦,甚至在C中更是如此,但它是唯一的方法,您的应用程序将独立于机器读写。
格式说明符本身表示参数是一个int
,由于数字是负数,printf
需要八个字符来显示int
大小的值的所有四个非零字节。0
修饰符告诉用零填充输出,而2
修饰符则告诉输出我建议最小输出长度应为两个字符。据我所知,printf
没有提供指定最大宽度的方法,字符串除外
现在,您只传递了一个char
,因此barex
告诉函数使用传递的完整int
——这是由于“…
”参数的默认参数提升。请尝试hh
修饰符,告诉函数将参数视为一个char
:
printf("%02hhx", b[i]);
您看到的是从char到int的保符号转换。这种行为是由于在您的系统上,char是有符号的(注意:并非所有系统上都有char的符号)。如果位模式使字符的值为负值,则会导致负值。将这样的字符提升为int将保留符号,并且int也将为负值。请注意,即使不放置(int)
明确地说,编译器将在传递到printf时自动将字符升级为int。解决方案是首先将您的值转换为无符号字符
:
for (i=0; i<4; i++)
printf("%02x ", (unsigned char)b[i]);
然后,在使用printf打印时,您不需要任何强制转换。当您尝试使其与网络无关时,将结构转换为字符或字节会导致问题。为什么不现在解决这个问题呢?您可以使用多种不同的技术,所有这些技术都很可能是非常有用的您的“便携性”比您正在尝试的要高。例如:
- 在POSIX/Unix世界中,通过函数
htonl
、htons
、ntohl
和ntohs
以与机器无关的方式在网络上发送数字数据早已得到处理。例如,请参阅FreeBSD或Linux系统上的手册页
- 在JSON和本机表单之间转换数据时,与网络传输延迟相比,程序在JSON和本机表单之间转换数据所花费的时间可能微不足道
除非你有非常令人信服的测量结果表明每一个八位元都是宝贵的,不要这样做。使用可读的ASCII协议,如,或IETF编纂的许多其他优秀互联网协议之一
如果您确实必须使用二进制格式,那么在结构中挤出字节仍然是不安全的,因为不同主机的字节顺序、基本大小或对齐约束可能不同。您必须设计wire protcol以使用定义良好的大小和定义良好的字节顺序。对于您的实现,可以使用 ntohl(3)
或使用移位和屏蔽将字节放入流中。无论您做什么,请确保您的代码在big-endian和little-endian主机上产生相同的结果。字符数组的签名性不是问题的根源!(这是一个问题,但不是唯一的问题。)
对齐!这是这里的关键词。这就是为什么你永远不应该尝试将结构当作原始内存。编译器(和各种优化标志)、操作系统和月相都会对“相邻”内存中的实际位置做出奇怪和令人兴奋的事情结构中的字段。例如,如果您有一个结构,其中一个char后跟一个int,那么整个结构将在内存中包含八个字节——char,3个空白的无用字节,然后是int的4个字节。机器喜欢这样做,以便结构可以干净地放在内存页上,诸如此类
在当地大学学习机器体系结构入门课程。同时,正确序列化。不要像对待字符数组一样对待结构。当你要发送它时,只需使用: (字符*)和自定义数据包
转换。对我有效。字符不总是有符号的。有符号字符是有符号的。字符的符号大小取决于编译器。在任何情况下,字符、有符号字符和无符号字符是三种不同的类型。“字符”显然,在这个上下文中是有符号的,因为符号扩展是在参数传递给stack.dreamlax上的printf时发生的,实际上他的答案很好:)只是想告诉他们,在另一个系统上,输出很可能是其他的(非负的),因为char也可能是未签名的。这取决于编译器。Downvote和flagged,这不是他的问题的答案;甚至不接近答案。如果有人问如何正确地做某件事,你真的应该避免灌输他们,如果这样做是好主意还是不好,尤其是我非常不同意你在第一段,特别是如果
for (i=0; i<4; i++)
printf("%02x ", (unsigned char)b[i]);
unsigned char *b = (unsigned char *)&a;