c语言中warning:hex escape sequence out of range的探究
起因:
在和 clown 说 memcpy
函数拷贝字符串是不会被 \x00
截断这个结论之前,为了避免翻车(尽管我有九成九的把握),我自己写了个代码进行验证,结果发现了一些奇怪的事情…
探究
|
先将一个字符串常量中夹杂一个空字符 \x00
,然后用 memcpy
函数进行拷贝到新的数组中,最终用 write
函数进行输出,这样就能清楚的判断 \x00
会不会造成截断效果
运行起来的效果如下
看到 \x00
后面的字符串 gklm
成功输出后,我就去告诉了 clown \x00
并不会截断 memcpy
函数的结论,正准备收工时,我突然发现字符 ef
没了😮
本着不放弃小细节的原则,我并不打算得过且过。
先使用了 gdb
进行调试
查看 memcpy
函数的第二个参数要拷贝的字符串为 abcd\357gklm
,这个 \357
我第一时间没反应过来,以为这里是出问题了?😨 不过联想到这里的数据原本是字符 e
和 f
,我猜测可能是被解析成十六进制数据了,用计算器查看了一下发现 357
是八进制,表示为十六进制是 \xef
上网查资料,得知编译器看到 \x
时,它会尝试解析后面的所有十六进制数字,直到遇到一个非十六进制数字。在上面的代码中,它看到了 \x00ef
将其解析为一个单一的字符 \xef
,而并非是我希望的空字符 \x00
和字符 e
f
我又好奇如果给的数据为 \x01ef
,那么在内存中这个值会如何表示?因为之前的高位 00
是可以省略的,但这个高位的 \x01
无法省略
|
发现在编译时就已经给了 warning: hex escape sequence out of range
,这表示十六进制转义序列超出范围,在 \x
之后的第三个字符如果依然可以表示十六进制(0~9
a~f
),会一起转义,这里的 \x01ef
超过了 ASCII
码的范围
在使用 gdb
调试时,只能看到 \xef
,高位的 \x01
已经不见了。这因为十六进制转义序列的长度虽然没有限制,但在实际使用中,一个字符只能包含8个比特(即1个字节),所以这里是直接舍弃了高位的数据,即使写成 \x11223344
最后留下的也只有 \x44
如何达到我想要结果?
在下面的参考文章中对这个进行了说明,只需要将字符串拆开就可以正常来显示了
|
如此不但验证了上面 memcpy
函数不会被 \x00
截断拷贝的结论,并且还发现了两个有意思的现象
\x0061
实际上为\x61
因为编译器会尝试解析后面的所有十六进制数字,直到遇到一个非十六进制数字,此处的\x00
为高位可以被省略,属于正常代码\x0161
实际上还是\x61
,因为\x0161
尝试被解析为一个十六进制的数据,导致超出最大的转义序列范围,只保留了最低位并且编译器给了warning