将不可打印的ASCII字符转换为二进制

将不可打印的ASCII字符转换为二进制,c,C,我正在尝试将一个不可打印的ASCII字符字符串转换为二进制。代码如下: int main(int argc, char *argv[]) { char str[32]; sprintf(str,"\x01\x00\x02"); printf("\n[%x][%x][%x]",str[0],str[1],str[2]); return 1; } 我希望输出应该是[1][0][2],但它会打印[1][0][4] 我在这里做错了什么?C字符串以空字节结尾,因此spr

我正在尝试将一个不可打印的ASCII字符字符串转换为二进制。代码如下:

int main(int argc, char *argv[])
{
    char str[32];
    sprintf(str,"\x01\x00\x02");

    printf("\n[%x][%x][%x]",str[0],str[1],str[2]);
    return 1;
}
我希望输出应该是[1][0][2],但它会打印[1][0][4]


我在这里做错了什么?

C字符串以空字节结尾,因此
sprintf
只能读取到
\x00
。相反,您可以使用
memcpy
()或使用

char str[32] = "\x01\x00\x02";

sprintf
操作在字符串文本中的
\x00
的第一个实例处结束,因为NUL(U+0000)在C中终止字符串。(当您在字符串文本中编写
\x00
时,编译器不会抱怨,这可以说是该语言的一个错误特性。)因此
str[2]
访问未初始化的内存,程序有权打印完全无意义的内容,甚至崩溃

要做您想做的事情,只需删除
sprintf

int main(void)
{
    static const unsigned char str[32] = 
    { 0x01, 0x00, 0x02 };  // will be zero-filled to declared size

    printf("[%02x][%02x][%02x]\n", str[0], str[1], str[2]);

    return 0;
}
(二进制数据应该总是存储在无符号字符的数组中,而不是普通字符;或者
uint8_t
(如果有的话)。因为U+0000终止字符串,我认为使用数组文本而不是字符串文本来编写嵌入的二进制数据是更好的方式;但是它更容易键入。
static const
只是因为数据是n编译时曾经修改过并且已知;如果没有它,程序可以运行。如果不打算使用它们,请不要声明
argc
argv
。从
main
返回零,而不是一,表示成功完成。)


(由于其他原因,使用
sprintf
是个坏主意:例如,如果二进制块包含
\x25
(在ASCII中也称为
%
),它将尝试读取其他要格式化的参数,然后再次打印完全无意义或崩溃。如果您有充分的理由不只是使用静态初始化数据,那么复制二进制数据块的正确方法是
memcpy

“\x00”终止作为sprint()的第二个参数的格式字符串过早。显然这是无意的,但sprint()无法确定第一个NUL不是最后一个NUL。因此,它使用的格式字符串实际上比您希望传递的短。

我认为这与“\x00”有关。例如,如果我将上面示例中的“\x00”替换为\x01,则输出为文件[1][1] [2]…仍然混淆注意:要以可移植的方式确定
int
是否为可打印字符,请使用
#include isprint(x)
。您可以这样写..我现在理解..thks+1,因为此解决方案通过使用无符号字符很好地处理非ASCII类
'\x80'
。然后将其打印为“[0x80]”,而不是“[FFFFFFFFFF 80]”。