在c中打印/存储n字节的u_char指针?
Posted
技术标签:
【中文标题】在c中打印/存储n字节的u_char指针?【英文标题】:Print/store n bytes of u_char pointer in c? 【发布时间】:2019-03-03 03:59:01 【问题描述】:我正在尝试创建一个函数来打印/存储 u_char 指针的前 n 个字节。这是我目前拥有的(只是试图打印第一个值),但它不起作用。
void print_first_value(const u_char * p)
printf("%d", p[0]);
我也试过这个:
void print_first_value(const u_char * p)
printf("%d", &p[0]);
我将如何进行这项工作?最后我想遍历*p
中的各个值,但我只能通过这段代码在p
指向的地址打印整个字符串。
void print_first_value(const u_char * p)
printf("%s", p);
所以我打印的是数据包,抱歉我没有提到。最后一个 sn-p 代码以十六进制打印一个数据包,所以像0050 5686 7654 0000...
这样我想打印/存储某些索引处的值。所以我想要前两个区块00505686
,然后是接下来的两个,依此类推。
【问题讨论】:
您能否更具体地说明什么不起作用?您期望的输出与使用每个功能得到的输出是什么?我尝试了你的第一个函数,它打印了第一个u_char
作为数字。
第一个函数是正确的。可能是您使用了错误的转换字符串? "%d" 用于十进制转换,打印一个数值。 "%c" 用于字符:try, printf("%c", p[0]);
什么是'p'
?它是指向unsigned
值的指针吗,例如unsigned u = 0xdeadbeef; unsigned char *p = (unsigned char *)&u;
?或者它是指向unsigned char
数组的指针,例如char s[] = "somestring"; unsigned char *p = (unsigned char *)s;
?
@DavidC.Rankin 看到我的编辑,抱歉我之前没有包含它。
@Citut - 我添加了一个答案来处理 "packet"
中的值,而不是字符串。您需要确定数据包中数据的 byteorder(在答案中解释)如果您有任何问题,请告诉我。
【参考方案1】:
首先,关于您的代码的几点说明:
u_char
不是标准类型。 unsigned char
是这种类型的标准拼写方式。虽然您可能在代码库中使用了typedef
(例如typedef unsigned char u_char;
),但最好使用标准类型,尤其是在使用typedef
而不使用typedef
本身发布代码时。
&p[0]
和 p
在 C 中的含义完全相同,无论 p
的值如何(假设它是一个指针)。同样的道理,p[0]
和 *p
也意味着同样的事情。我将在其他示例中仅使用 p
和 *p
,但请记住等效性。
unsigned char
是一个整体类型。这意味着它的值是一个整数。该值也可以解释为字符这一事实是偶然的。这很快就会变得非常重要。
现在,至于您的 sn-ps。让我们以相反的顺序进行。如您所知,最后一个只是打印字符串。
第二个是未定义的行为。 printf("%d", p)
(&p[0]
= p
,还记得吗?)将指针作为参数传递(p
的类型为 const unsigned char *
),但 %d
需要 int
。参数必须与格式说明符指示的类型匹配;否则是错误的。它可能会“工作”(例如,不会崩溃),但这是你绝对不应该做的事情。这不是有效的 C。
第一个是最有趣的。首先,printf("%d", *p)
不是未定义的行为,不像第二个 sn-p 的情况。 *p
是 const unsigned char
(指针已被取消引用),并且任何比 int
窄的类型都会在可变参数列表中提升为 int
(printf
定义为 int printf(const char *, ...)
;, ...
在end 表示它接受任意数量的任意类型的参数,由于这个原因,它通常被称为可变参数),所以这是有效的。
事实上,它有效。让我们尝试使用它的完整程序:
#include <stdio.h>
void print_first_value (const unsigned char * p)
printf("%d", *p);
int main (void)
char str[] = "Hello world!";
print_first_value(str);
return 0;
假设您没有使用特别奇怪的计算机或操作系统,您会以这种方式打印72
。这没有错! 72
恰好是内部表示 ASCII 中的大写字母 H 的数字(称为 codepoint)。还记得我说过unsigned char
是一个整数类型吗?这就是它的意思:它的值实际上是一个数字。您要求您的计算机打印该号码,它确实做到了。
如果你想打印这个数字代表的字符,你有两个选择:使用%c
作为printf
中的格式说明符(告诉它打印字符)或使用putchar
/ putc
函数(采用单个数字并打印它们所代表的字符)。让我们选择后者:
#include <stdio.h>
void print_first_character (const char * p)
// it doesn't matter if it is unsigned or signed,
// because we're just printing the character
putchar(*p);
int main (void)
char str[] = "Hello world!";
print_first_character(str);
return 0;
现在您将收到H
。到达某个地方!现在,要打印字符串中的所有个字符,我们需要知道一个额外的细节:在字符串中所有有意义的字符之后,最后一个总是零。如数字零,而不是字符'0'
。 (这通常写为'\0'
,但这与零相同。)所以,我们开始吧:
#include <stdio.h>
void print_first_character (const char * p)
putchar(*p);
int main (void)
char message[] = "Hello world!";
const char * str = message; // initialize the pointer to the beginning of the string
while (*str) // while *str isn't zero
print_first_character(str); // print the character...
str ++; // ...and advance to the next one
putchar('\n'); // let's print a newline too, so the output looks nicer
return 0;
我们开始吧! Hello world!
将被打印出来。当然,puts("Hello world!");
也会做同样的事情,但这不是那么有趣,是吗?
【讨论】:
努力(而且格式很好),但可以肯定的是,我认为您必须找出p
指向什么?符号不同的字符数组?、无符号值?和无符号字符数组?您已经涵盖了第 1 部分,但请尝试确保 OP 不是在谈论案例 2 或 3。
@DavidC.Rankin 在将字符打印为字符时,字符的签名是无关紧要的。此外,我们知道他发布的第三个 sn-p 打印了 something,这意味着它必须指向一个以 null 结尾的字符数组——换句话说,一个字符串。
是的,我知道,一个字符无论如何都会转换为 unsigned char。不同之处在于回答他关于如何输出所有字节的最终问题。 (我猜他确实提到了string
,因此可以将其范围缩小到您的情况)在这种情况下,打印所有内容的函数可能只是while (*p) putchar (*p++);
。
@aaaaaa123456789 做得好,非常感谢。我做了一点修改,我不确定这是否重要,但我正在打印数据包(十六进制格式)。
@Citut 如果你想打印一个十六进制的unsigned char
,%02hhX
可以做到。 0
表示以前导零作为前缀是值太小,2
无法填充到长度 2,hh
是修饰符,表示该值是 char
,而不是 int
,并且X
表示打印十六进制数字,A-F 使用大写字母(x
使用小写)。【参考方案2】:
根据您的编辑,您正在打印数据包
啊哈!这更有意义。当您创建一个指向 unsigned
值的 unsigned char
指针时,您有一个指向内存中值开头的指针,但该值的存储方式将取决于机器的字节序和 字节顺序 em> 数据包中的字节数。
简单地存储/打印出当前存储在内存中的字节并不困难,存储/打印每两个字节也不困难。每个都可以用类似的东西来完成:
/* all bytes stored in memory */
void prn_all (const unsigned char *p, size_t nbytes)
while (nbytes--)
printf ("0x%02x\n", p[nbytes]);
/* each 2-bytes stored in memory */
void prn_two (const unsigned char *p, size_t nbytes)
while (nbytes--)
printf ("%02x", p[nbytes]);
if (nbytes % 2 == 0)
putchar ('\n');
...
unsigned u = 0xdeadbeef;
unsigned char *p = (unsigned char *)&u;
prn_all (p, sizeof u);
putchar ('\n');
prn_two (p, sizeof u);
会导致:
$ /bin/prn_uchar_byte
0xde
0xad
0xbe
0xef
dead
beef
现在要注意了。既然你提到了"packet"
,根据数据包是network-byte-order还是host-byte-order,你可能需要一个转换(或者简单的位移) 以按您需要的顺序获取字节。 C 提供了在 network-byte-order 和 host-byte-order 之间转换的函数,反之亦然,man 3 byteorder htonl, htons, ntohl, ntohs
。需要,因为网络字节顺序是大端,而普通 x86 和 x86_64 是小端。如果你的包是网络字节序并且你需要主机字节序,你可以简单地调用ntohs
(网络到主机short
)将每个两字节值转换为主机顺序,例如
/* each 2-bytes converted to host byte order from network byte order */
void prn_two_host_order (const unsigned char *p, size_t nbytes)
for (size_t i = 0; i < nbytes; i+=2)
uint16_t hostorder = ntohs (*(uint16_t*)(p+i));
printf ("%04" PRIx16 "\n", hostorder);
...
prn_two_host_order (p, sizeof u);
结果:
efbe
adde
(注意:ntohs
的原型(以及所有字节顺序转换)使用 exact-width 类型 uint16_t
和 uint32_t
——打印宏在inttypes.h
中——它还自动包含stdint.h
)
您将确定您在"packets"
中的顺序,以了解是否需要进行字节顺序转换。这将取决于您如何获取数据。
把它放在一个简短的例子中,你可以这样做:
#include <stdio.h>
#include <inttypes.h>
#include <arpa/inet.h>
/* all bytes stored in memory */
void prn_all (const unsigned char *p, size_t nbytes)
while (nbytes--)
printf ("0x%02x\n", p[nbytes]);
/* each 2-bytes stored in memory */
void prn_two (const unsigned char *p, size_t nbytes)
while (nbytes--)
printf ("%02x", p[nbytes]);
if (nbytes % 2 == 0)
putchar ('\n');
/* each 2-bytes converted to host byte order from network byte order */
void prn_two_host_order (const unsigned char *p, size_t nbytes)
for (size_t i = 0; i < nbytes; i+=2)
uint16_t hostorder = ntohs (*(uint16_t*)(p+i));
printf ("%04" PRIx16 "\n", hostorder);
int main (void)
unsigned u = 0xdeadbeef;
unsigned char *p = (unsigned char *)&u;
prn_all (p, sizeof u);
putchar ('\n');
prn_two (p, sizeof u);
putchar ('\n');
prn_two_host_order (p, sizeof u);
(注意:一些系统使用标题netinet/in.h
而不是arpa/inet.h
进行手册页中列出的字节顺序转换)
使用/输出的完整示例
$ /bin/prn_uchar_byte
0xde
0xad
0xbe
0xef
dead
beef
efbe
adde
您可以存储值而不是打印 - 但这留给您。看看事情,如果你有问题,请告诉我。
【讨论】:
以上是关于在c中打印/存储n字节的u_char指针?的主要内容,如果未能解决你的问题,请参考以下文章