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