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

查看:691
本文介绍了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\r\n", 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;
    }
}

这是结果:

"JW\xd6\x96'$$LK\x90\xbbar: 3030\r\r\n"

这是在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\r\n", (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.)

显然,按照c标准要求,传递给printfunsigned char自变量未被提升为intunsigned int.

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\r\n", (unsigned int)foo, (unsigned int)bar);

(通常不需要\r,因为\n会自动转换为文本流的系统行尾顺序,但也许Keil C51的工作方式有所不同.)

(The \r normally wouldn't be necessary, since \n 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,因为不可能将char(或unsigned charsigned char)参数传递给printf.任何此类参数将被提升为int或可能的unsigned int.我从这以及您所遇到的错误中推断,Keil C51不会将可变参数推广为狭窄的参数,尤其是>参数不会被提升为 c4>或unsigned 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\r\n", 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.

也可以使用"%02bx"进行铸造,但是使用"%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天全站免登陆