我试图将一个不可打印的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
(like this)或简单地初始化
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;
}
(二进制数据应始终存储在unsigned char数组中,而不是普通char;如果有的话,则应存储在uint8_t
。因为U + 0000终止字符串,我认为使用数组文字而不是字符串文字来编写嵌入式二进制数据是更好的方式;但它更多的是打字.static const
只是因为数据永远不会被修改并且在编译时就知道;程序在没有它的情况下可以工作。如果你不打算使用它们,不要声明argc
和argv
。返回0,不是一个,来自main
表示成功完成。)
(使用sprintf
你使用它的方式是出于其他原因的一个坏主意:例如,如果你的二进制块包含\x25
(在ASCII中也称为%
),它会尝试读取要格式化的其他参数,以及再次打印完全废话或崩溃。如果你有充分的理由不仅使用静态初始化数据,复制二进制数据块的正确方法是memcpy
。)
“\ x00”终止格式字符串,这是sprint()过早的第二个参数。显然这是无意的,但sprint()没有办法弄清楚第一个NUL不是最后一个NUL。因此,它所使用的格式字符串实际上比您想要传递的格式字符串短。