如何在C语言中将整数转换为Unicode字符串?

5

我正在开发一个嵌入式USB项目的固件。我想要使用的生产编程器会在指定的内存地址自动将序列号写入设备闪存中。编程器将序列号以十六进制数字的形式存储在指定数量的字节中。例如,如果我告诉它将序列号123456存储在地址0x3C00,我的内存将如下所示:

0x3C00  -  00
0x3C01  -  01
0x3C02  -  E2
0x3C03  -  40
//(123456 in Hex = 1E240)

问题在于,当我的主机应用程序从设备中读取序列号时,它需要一个Unicode字符数组。因此,我的序列号应该是…
{ '1','0',
  '2','0',
  '3','0',
  '4','0',
  '5','0',
  '6','0'}

因此,在我的固件中,我正在用C语言编写,是否有可能从flash中检索十六进制序列号,将其编码为unicode字符数组并将其存储在Ram变量中?


我认为示例数组应该这样编写 ushort [] serial = { '1', '2', '3', '4', '5', '6'} - user180326
我们可以假设你的C编译器能够理解Unicode吗? - user180326
5个回答

5

看起来您想要:

wsprintf(wchar_buffer, L"%d", serial_number)

(假设您的序列号适合一个32位整数。无论如何,wsprintf将会将您的序列号打印成一个wchar(unicode)字符串。)

wchar_t 不一定是16位的UCS2(它甚至不一定是Unicode)。 - caf
如果是这样的话,那确实如此。您应该能够阅读编译器文档以确定 wchar_t 是否具有所需的字符大小(如果不是,则如何设置标志使 wchar_t 执行所需操作)。 - JSBձոգչ
你能解释一下 L 代表什么吗? - Sean Letendre
1
@SeanLetendre 这意味着字符串字面值应被解释为“宽字符”(16位字符)字符串。 - JSBձոգչ

4
您应该能够使用类似于这样的东西:
wchar_t buf[10];
swprintf(buf, L"%d", your_int_value);

具体细节可能会因为您使用的C运行时库实现而有所不同。例如,您的swprintf()函数可能要求在buf中输入的字符数:

swprintf(buf, sizeof(buf)/sizeof(buf[0]), L"%d", your_int_value);

我怀疑在固件中实现这个可能性。 - Andrey
由于它是一个32位的数字,你必须使用%ld而不是%d。 - semaj
@Andrey:固件只是另一种名称的软件。固件可以有大量的运行时库可用。 - Greg Hewgill
据我所知,固件是在资源非常有限的设备上运行的软件,具有小内存和慢处理器,而编译器则是特殊的。没有人会链接Unicode库,只是为了将数组中的几个零增加几个。 - Andrey
@Andrey:我假设问题需要特定原因的Unicode序列号,可能是因为程序的其余部分已经使用了Unicode。显然,如果程序的其他部分不需要Unicode,则没有将此串行号转换为Unicode表示的任何理由。 - Greg Hewgill
显示剩余3条评论

2

不确定这段代码是否适用于您的设备,但让我们尝试一下。

char buffer[MAX_SIZE];
char unicodeBuffer[MAX_SIZE];
sprintf(buffer, "%d", i);
int len = strlen(buffer);
int i = 0;
for (int i = 0; i <= (len << 1) - 2; i++)
   unicodeBuffer[i] = i % 2 ? buffer[i] : 0;
unicodeBuffer[i + 1] = 0;
unicodeBuffer[i + 2] = 0;

这不起作用 - 它只复制了由sprintf创建的缓冲区一半的字符。 - caf

2

如果序列号适合32位,并且平台是大端和支持Unicode、32位整数和标准C库,则这很简单,就像其他答案所示。如果平台具有32位整数和8位字符但是是小端和/或不支持Unicode,而且如果序列号的长度可以变化,则下面的内容可能有用,尽管有点繁琐。

void extract_serial_number(unsigned char* address, unsigned int bytes, char* buffer) {
    unsigned int value = 0;
    char c, *start = buffer;
    while (bytes--) {                      /* read the serial number into an integer */
        value = value << 8;
        value |= *address++;
    }
    while (value > 0) {                    /* convert to 16 bit Unicode (reversed) */
        *buffer++ = '0' + value % 10;
        *buffer++ = '\0';
        value /= 10;
    }
    *buffer++ = '\0';
    *buffer++ = '\0';
    buffer -= 4;
    while (buffer > start) {               /* reverse the string */
        c = *buffer;
        *buffer = *start;
        *start = c;
        buffer -= 2;
        start += 2;
    }
}

2
如果您的嵌入式环境可以访问 sprintf,则以下内容应该可行:
#define MAX_SIZE(type) ((CHAR_BIT * sizeof(type) - 1) / 3 + 2)

/* Destination UCS2 buffer size must be at least 2*MAX_SIZE(int) */
void int_to_ucs2(char *dest, int q)
{
    char buffer[MAX_SIZE(q)];
    char *src = buffer;

    sprintf(buffer, "%d", q);

    do {
        *dest++ = *src;
        *dest++ = 0;
    } while (*src++);
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接