在 C 中是否有一种简单的方法将数字转换为十六进制 ASCII 字符?

发布于 2024-09-18 19:28:28 字数 641 浏览 6 评论 0原文

我正在为嵌入式设备编写 C 固件程序。我想通过串行端口发送一组十六进制字符值。有没有简单的方法将值转换为 ASCII 十六进制?

例如,如果数组包含 0xFF,我想发送 ASCII 字符串“FF”,或者对于十六进制值 0x3B,我想发送“3B”。

这通常是如何完成的?

我已经准备好串行发送函数,以便我可以执行此操作...

char msg[] = "Send this message";
SendString(msg);

并且 SendString 函数为传递的数组中的每个元素调用此函数:

// This function sends out a single character over the UART
int SendU( int c)
{
    while(U1STAbits.UTXBF);
    U1TXREG = c;
    return c;
}

我正在寻找一个允许我执行此操作的函数...

char HexArray[5] = {0x4D, 0xFF, 0xE3, 0xAA, 0xC4};
SendHexArray(HexArray);

//Output "4D, FF, E3, AA, C4"

I am working a C firmware program for an embedded device. I want to send an array of hex char values over the serial port. Is there a simple way to convert a value to ASCII hex?

For example if the array contains 0xFF, I want to send out the ASCII string "FF", or for a hex value of 0x3B I want to send out "3B".

How is this typically done?

I already have the serial send functions in place so that I can do this...

char msg[] = "Send this message";
SendString(msg);

and the SendString function calls this function for each element in the passed array:

// This function sends out a single character over the UART
int SendU( int c)
{
    while(U1STAbits.UTXBF);
    U1TXREG = c;
    return c;
}

I am looking for a function that will allow me to do this...

char HexArray[5] = {0x4D, 0xFF, 0xE3, 0xAA, 0xC4};
SendHexArray(HexArray);

//Output "4D, FF, E3, AA, C4"

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

天冷不及心凉 2024-09-25 19:28:46

如果您的编译器支持,您可以使用 itoa。否则,我会像 Nathan 的 & 中那样使用 sprintf 。马克的回答。如果支持 itoa 并且性能是一个问题,请尝试一些测试来确定哪个更快(过去的经验使我期望 itoa 更快,但是 YMMV)。

If your compiler supports it, you can use itoa. Otherwise, I'd use sprintf as in Nathan's & Mark's answers. If itoa is supported and performance is an issue, try some testing to determine which is faster (past experience leads me to expect itoa to be faster, but YMMV).

乜一 2024-09-25 19:28:44

sprintf 会做到这一点。

sprintf(dest, "%X", src);

sprintf will do it.

sprintf (dest, "%X", src);

安穩 2024-09-25 19:28:42

我将从数组查找开始。

char *asciihex[] = {
    "00", "01", "02", ..., "0F",
    "10", "11", "12", ..., "1F",
    ...,
    "F0", "F1", "F2", ..., "FF"
};

然后简单地查找一下...

SendString(asciihex[val]);

编辑

合并 Dysaster 的蚕食想法:

void SendString(const char *msg) {
    static const char nibble[] = {'0', '1', '2', ..., 'F'};
    while (*msg) {
        /* cast to unsigned char before bit operations (thanks RBerteig) */
        SendU(nibble[(((unsigned char)*msg)&0xf0)>>4]); /* mask 4 top bits too, in case CHAR_BIT > 8 */
        SendU(nibble[((unsigned char)*msg)&0x0f]);
        msg++;
    }
}

I'd start with an array lookup.

char *asciihex[] = {
    "00", "01", "02", ..., "0F",
    "10", "11", "12", ..., "1F",
    ...,
    "F0", "F1", "F2", ..., "FF"
};

and then simply look it up ...

SendString(asciihex[val]);

Edit

Incorporating Dysaster's nibbles idea:

void SendString(const char *msg) {
    static const char nibble[] = {'0', '1', '2', ..., 'F'};
    while (*msg) {
        /* cast to unsigned char before bit operations (thanks RBerteig) */
        SendU(nibble[(((unsigned char)*msg)&0xf0)>>4]); /* mask 4 top bits too, in case CHAR_BIT > 8 */
        SendU(nibble[((unsigned char)*msg)&0x0f]);
        msg++;
    }
}
三生路 2024-09-25 19:28:40

汇编语言时代8位微机的经典技巧是将一个半字节的转换分成两段。 0到9的值和10到15的值。然后简单的算术保存了16字节的查找表。

void SendDigit(int c) {
    c &= 0x0f;
    c += (c <= 9) ? '0' : 'A'-10;
    SendU(c);
}

void SendArray(const unsigned char *msg, size_t len) {
    while (len--) {
        unsigned char c = *msg++;
        SendDigit(c>>4);
        SendDigit(c);
    }
}

一些旁注是有序的。首先,这是可行的,因为数字和字母在 ASCII 中都是连续的。如果您不幸需要EBCDIC,这仍然可以用作字母“A”到“ F' 在那里也是连续的(但字母表的其余部分被分成三个跨度)。

其次,我更改了 SendArray() 的签名。我的版本小心地使缓冲区无符号,当计划将字节提升为某种更大的整数类型以进行算术时,这通常更安全。如果它们已签名,则像 nibble[(*msg)>>4] 这样的代码可能会尝试在数组中使用负索引,结果根本没有用处。

最后,我添加了一个长度参数。对于一般的二进制转储,您可能没有任何有意义的字节值用作结束标记。为此,计数更为有效。

编辑:修复了一个错误:对于超过 10 的数字,算术是 c + 'A' - 10,而不是 c + 'A'。感谢布鲁克斯·摩西抓住了这一点。

The classic trick from the 8-bit micro in assembly language era is to break the conversion of a nybble into two segments. The value from 0 to 9 and the value from 10 to 15. Then simple arithmetic saves the 16-byte lookup table.

void SendDigit(int c) {
    c &= 0x0f;
    c += (c <= 9) ? '0' : 'A'-10;
    SendU(c);
}

void SendArray(const unsigned char *msg, size_t len) {
    while (len--) {
        unsigned char c = *msg++;
        SendDigit(c>>4);
        SendDigit(c);
    }
}

A couple of side notes are in order. First, this works because the digits and letters are each in contiguous spans in ASCII. If you are unfortunate enough to want EBCDIC, this still works as the letters 'A' through 'F' are contiguous there as well (but the rest of the alphabet is broken into three spans).

Second, I've changed the signature of SendArray(). My version is careful to make the buffer be unsigned, which is generally safer when planning to promote the bytes to some larger integral type to do arithmetic. If they are signed, then code like nibble[(*msg)>>4] might try to use a negative index into the array and the result won't be at all useful.

Finally, I added a length parameter. For a general binary dump, you probably don't have any byte value that makes sense to use as an end sentinel. For that, a count is much more effective.

Edit: Fixed a bug: for digits over 10, the arithmetic is c + 'A' - 10, not c + 'A'. Thanks to Brooks Moses for catching that.

独享拥抱 2024-09-25 19:28:37

使用 sprintf 将数字写入字符串,然后使用现有的 SendString 函数通过 UART 发送该数字。当然,您可以一次执行一个数字:

char num_str[3];
sprintf( num_str, "%02X", 0xFF );
SendString(num_str);

%02X 是一个 printf 系列函数的“nofollow noreferrer">格式化字符串,它表示用 0 填充元素直到宽度为 2,并将元素格式化为十六进制数字。

02 部分确保当您想要打印 0x0F 时,您会在输出中得到 0F 而不仅仅是 F溪流。如果您使用小写的x,您将得到小写字符(例如ff 而不是FF)。

Write the number to a string using sprintf and then use your existing SendString function to send that over the UART. You can, of course, do this one number at a time:

char num_str[3];
sprintf( num_str, "%02X", 0xFF );
SendString(num_str);

%02X is a format string for the printf family of functions, it says pad the element with 0s until width 2 and format the element as a hexadecimal number.

The 02 part ensures that when you want to print 0x0F that you get 0F instead of just F in the output stream. If you use a lowercase x you'll get lowercase characters (e.g. ff instead of FF).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文