printf() 导致乱码 [英] printf() results in gibberish

查看:54
本文介绍了printf() 导致乱码的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有这个代码:

unsigned char *command = "0000";
unsigned char foo = (hex_char_to_int(command[0]) << 4) | hex_char_to_int(command[1]);
unsigned char bar = (hex_char_to_int(command[2]) << 4) | hex_char_to_int(command[3]);
printf("foo: %02x, bar: %02x
", foo, bar);

它使用这个功能:

unsigned char hex_char_to_int(unsigned char ch) {
    switch (ch){
        case '0': return 0;
        case '1': return 1;
        case '2': return 2;
        case '3': return 3;
        case '4': return 4;
        case '5': return 5;
        case '6': return 6;
        case '7': return 7;
        case '8': return 8;
        case '9': return 9;
        case 'A': return 0xA;
        case 'B': return 0xB;
        case 'C': return 0xC;
        case 'D': return 0xD;
        case 'E': return 0xE;
        case 'F': return 0xF;
        case 'a': return 0xA;
        case 'b': return 0xB;
        case 'c': return 0xC;
        case 'd': return 0xD;
        case 'e': return 0xE;
        case 'f': return 0xF;
        default: return 0;
    }
}

这是结果:

"JWxd6x96'$$LKx90xbbar: 3030

"

这是在 Keil C51 编译器上,在 AT89C55WD 上,printf() 通过串行端口.

This is on the Keil C51 compiler, on an AT89C55WD, with printf() going over a serial port.

发生了什么事?

编辑

我把 printf 行改成 ​​

I change the printf line to

printf("%02x%02x
", (unsigned int)foo, (unsigned int)bar);

所以它看起来像 printf 中的一个错误.程序员们,请永远不要制作一个说谎的调试工具.求求你了.

So it looks like a bug in printf. Please, programmers, never make a debugging tool that lies. I beg you.

推荐答案

据我所知,该代码应该可以在任何符合标准的 C 编译器下工作.

As far as I can tell, that code should work under any conforming C compiler.

我没有使用过 Keil C51,但我看到一些迹象表明它并不完全符合 C 标准的要求,例如在促进窄类型方面.

I haven't used Keil C51, but I've seen some indications that it doesn't entirely follow the requirements of the C standard, for example in promoting narrow types.

(此答案之前包含了许多可能的建议,其中大部分没有成功.如果您好奇,请查看编辑历史记录.)

(This answer previously included a number of possible suggestions, most of which didn't pan out. If you're curious, see the edit history.)

显然,传递给 printfunsigned char 参数 not 提升为 intunsigned int,按照 c 标准的要求.

Apparently an unsigned char argument passed to printf is not promoted to int or unsigned int, as the c standard requires.

要在保持代码合理可移植的同时解决此问题,请添加强制转换以将 foobar 的值显式转换为 unsigned int:

To work around this while keeping your code reasonably portable, add casts to explicitly convert the values of foo and bar to unsigned int:

printf("foo: %02x, bar: %02x
", (unsigned int)foo, (unsigned int)bar);

( 通常不需要,因为 会自动转换为系统的文本流行结束序列,但也许 Keil C51 的工作方式不同.)

(The normally wouldn't be necessary, since is automatically converted to the system's line ending sequence for text streams, but perhaps Keil C51 works differently.)

同样,它应该可以工作,但是这个改变可能会解决 Keil 51 的 bug 特性.

Again, it should work either way, but this change might work around a bug feature of Keil 51.

更新:

我刚刚查看了 Keil C51 的在线文档.printf 的文档显示了一些非标准特性,包括 bB 来指定 char 类型,就像 l 指定 long 类型一样.

I just checked the online documentation for Keil C51. The documentation for printf shows some non-standard features, including b and B to specify char types, just as l specifies long types.

bB 在标准 C 中不是必需的,因为不可能传递 char(或 unsigned charsigned char) 参数到 printf;任何这样的参数都将被提升为 int,或者可能是 unsigned int.我由此推断,以及您遇到的错误,Keil C51 不会将窄参数提升为可变参数函数,特别是 unsigned char 参数是 not 提升为 intunsigned int.

b and B are not necessary in standard C, since it's not possible to pass a char (or unsigned char, or signed char) argument to printf; any such argument will be promoted to int, or possibly unsigned int. I infer from this, and from the error you've run into, that Keil C51 doesn't promote narrow arguments to variadic functions, and in particular that an unsigned char argument is not promoted either to int or to unsigned int.

这就解释了原因

printf("%02x", foo);

没用,为什么

printf("%02x", (unsigned int)foo);

做了.

此编译器以小型 8 位微处理器为目标.您不希望隐式扩展单字节参数是有道理的.作者显然选择了性能而不是一致性——这是一个完全有效的决定.(如果文档对此更明确,或者我可能遗漏了一些东西,那就太好了.)

This compiler targets a small 8-bit microprocessor. It makes sense that you wouldn't want to implicitly widen single-byte arguments. The authors apparently chose performance over conformance -- which is a perfectly valid decision. (It would be nice if the documentation were more explicit about this, or maybe I've missed something.)

以十六进制打印 unsigned char 值的推荐方法可能是:

Probably the recommended way to print unsigned char values in hex would be:

printf("foo: %02bx, bar: %02bx
", foo, bar);

请注意,这是 Keil C51 特有的,并且会使您的代码无法移植到其他平台.但话又说回来,为在如此小的系统上运行而编写的代码无论如何都不太可能是可移植的.

Note that this is specific to Keil C51, and makes your code non-portable to other platforms. But then again, code written to run on such a small system isn't likely to be portable anyway.

转换为 unsigned int 也应该可以工作,但使用 "%02bx" 可能在时间和代码大小上更有效,因为参数可以作为单个字节传递.

Casting to unsigned int, as I suggested previously, should also work, but using "%02bx" might be more efficient in time and code size, since the arguments can be passed as single bytes.

这篇关于printf() 导致乱码的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆