我正在尝试将一串不可打印的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]。
我在这里做错了什么?
答案 0 :(得分:6)
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;
}
(二进制数据应该始终存储在 unsigned char的数组中,而不是普通的char;或uint8_t
如果有的话。因为U + 0000终止了字符串,我认为它的风格更好使用数组文字而不是字符串文字来编写嵌入式二进制数据;但更多的是输入。static const
只是因为数据永远不会被修改并且在编译时就已知;程序在没有它的情况下就可以工作.Don'如果你不打算使用它们,请声明argc
和argv
。从main
返回零而不是一,表示成功完成。)
(使用sprintf
的方式出于其他原因是个坏主意:例如,如果你的二进制块包含\x25
(在ASCII中也称为%
),它会尝试读取要格式化的其他参数,并再次打印完全无意义或崩溃。如果你有充分的理由不仅使用静态初始化数据,那么复制二进制数据块的正确方法是{{1 }}。)
答案 1 :(得分:5)
C字符串以空字节结尾,因此sprintf
仅读取\x00
。相反,您可以使用memcpy
(like this)或只使用
char str[32] = "\x01\x00\x02";
答案 2 :(得分:3)
“\ x00”终止格式字符串,这是sprint()过早的第二个参数。显然这是无意的,但sprint()没有办法弄清楚第一个NUL不是最后一个NUL。因此,它所使用的格式字符串实际上比您想要传递的格式字符串短。