-2

我希望这很简单。这些是由反斜杠分隔的 20 个十六进制值\,C 编译器确实使它们成为 33 个字符的字符串,因为\NUMBER单个值\NUMBER+ALPHA= 2 个字节和\ALPHA+NUMBER2 个字节。

char str[] =
"\b3\bc\77\7\de\ed\44\93\75\ce\c0\9\19\59\c8\f\be\c6\30\6";
//when saved is 33 bytes

我的问题是在它被保存到磁盘上的 33 个字节之后,我们可以(在读取 33 个字节之后)重新制作我们在 C 中的相同表示吗?所以程序打印"\b3\bc\77\7\de\ed\44\93\75\ce\c0\9\19\59\c8\f\be\c6\30\6",这里有问题解决者吗?

"\b3\bc\77\7\de\ed\44\93\75\ce\c0\9\19\59\c8\f\be\c6\30\6";
//when read back program should output this ^
4

1 回答 1

2

您拥有的字符串文字:

"\b3\bc\77\7\de\ed\44\93\75\ce\c0\9\19\59\c8\f\be\c6\30\6"

将产生根据C89的未定义行为(不确定 C89 的源是否可以信任,但我在下面的观点仍然成立)和根据C11标准的实现定义的行为。特别是,\d, \e, \9,\c是标准中未定义的转义序列。gcc不会抱怨\e,因为它是代表 ESC 的 GNU 扩展。

由于存在实现定义的行为,因此我们有必要知道您使用的是什么编译器,因为结果可能会有所不同。

另一件事是,您没有清楚地表明您在编译后知道字符串的内容。(更清晰的显示方法是包含字符串在内存中的样子的十六进制转储,并显示您如何知道转义序列)。

这就是编译器识别看起来像十六进制字符串的方式:

String: \b  3 \b  c \77 \7 \d  e \e  d \44 \9  3 \75 \c  e \c 0  \9 \1  9 \5  9 \c  8 \f \b  e \c  6 \20 \6
Char:   \b  3 \b  c \77 \7  d  e \e  d \44 \9  3 \75  c  e  c 0   9 \1  9 \5  9  c  8 \f \b  e  c  6 \20 \6
Hex:    08 33 08 63  3f 07 64 65 1b 64  24 39 33  3d 63 65 63 30 39 01 39 05 39 63 38 0c 08 65 63 36  18 06 00

拐弯抹角就够了。假设您正在使用gcc编译代码(忽略警告)。运行代码时,整个代码char[]使用fwrite. 我还假设源代码中只使用小写字符。

您应该将所有可能的转义序列\xy(看起来像 2 位十六进制数)映射到 1 或 2 个字节的序列。它们的数量并不多,您可以编写一个程序来模拟编译器的行为:

  • 如果xa, b, f(其他转义序列,如\n不是十六进制数字)和e(由于 GNU 扩展)中的任何一个。它被映射到特殊字符。
  • (如果您在源代码中使用大写字符,请注意\E映射到 ESC)
  • 如果xy形成一个有效的八进制序列。它映射到具有相应值的字符。
  • 如果x形成一个有效的八进制序列。它映射到具有相应值的字符。
  • 否则,x保持不变。
  • 如果y不消耗,则y保持不变。

请注意,实际char可能来自 2 种不同的方式。例如,\fand\14将映射到相同的char. 在这种情况下,可能无法取回源中的字符串。您最多可以猜测源中的字符串是什么。

以您的字符串为例,开头,08并且33可以来自\b3,但也可以来自\10\63

使用映射生成,有些情况下映射很清楚:大于3f不能来自八进制转义序列的十六进制,并且必须来自对原始字符串中字符的直接解释。由此可知,如果e遇到,一定是looks-like-hex序列中的第二个字符。

您可以使用地图作为指导,并将模拟作为检查地图是否会返回 ASCII 码的方法。在对源代码中声明的字符串一无所知的情况下,您最多可以得出源代码中原始(损坏)字符串的候选列表。如果您至少知道源代码中字符串的长度,则可以减少候选列表的大小。

于 2013-02-02T17:29:40.010 回答