あなたが持っている文字列リテラル:
"\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
いないエスケープ シーケンスです。ESC を表す GNU 拡張であるため、gcc
について文句を言うことはありません。\e
実装定義の動作があるため、結果が異なる可能性があるため、使用しているコンパイラを知る必要があります。
もう 1 つのことは、コンパイル後に文字列の内容を認識していることを明確に示していないことです。(表示するより明確な方法は、文字列がメモリ内でどのように見えるかの 16 進ダンプを含め、エスケープ シーケンスをどのように認識しているかを示すことです)。
これは、16 進数のような文字列がコンパイラによってどのように認識されるかです。
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 桁の 16 進数のように見えるすべての可能なエスケープ シーケンスを 1 または 2 バイトのシーケンスにマップする必要があります。それらの数はそれほど多くなく、コンパイラーの動作をシミュレートするプログラムを作成できます。
- , , (その他のエスケープ シーケンスは 16 進数ではありません) および(GNU 拡張による) の
x
いずれかである場合。特殊文字にマップされます。a
b
f
\n
e
- (ソース コードで大文字を使用する場合は、
\E
ESC にマップされることに注意してください)
xy
有効な 8 進シーケンスを形成する場合。対応する値を持つ文字にマップされます。
x
有効な 8 進シーケンスを形成する場合。対応する値を持つ文字にマップされます。
- そうでなければ、
x
同じままです。
y
消費されなければy
そのまま。
実際のchar
値は 2 つの異なる方法で取得できることに注意してください。たとえば、\f
と\14
は同じ にマップされchar
ます。このような場合、ソース内の文字列を取得できない可能性があります。できることは、ソース内の文字列が何であるかを推測することです。
08
最初に文字列を例として使用し、から取得することも33
できますが\b3
、 から取得することもできます\10\63
。
マップ生成を使用すると、マッピングが明確な場合があります。16 進数より大きい 16 進数は3f
、8 進数のエスケープ シーケンスから取得できず、元の文字列の文字を直接解釈して取得する必要があります。e
このことから、 が検出された場合、それは 16 進数のように見えるシーケンスの 2 番目の文字でなければならないことがわかります。
マップをガイドとして使用し、シミュレーションを方法として使用して、マップが ASCII コードを生成するかどうかを確認できます。ソース コードで宣言されている文字列について何も知らなくても、派生できるのはソース コード内の元の (壊れた) 文字列の候補のリストだけです。少なくともソース コード内の文字列の長さがわかっている場合は、候補のリストのサイズを減らすことができます。