以字符串形式访问字符的混淆方式

erj*_*jot 7 c++ obfuscation

我今天发现了一段有趣的代码:

auto ch = (double(), (float(), int()))["\t\a\r\n\0"]["abcdefghij"];
Run Code Online (Sandbox Code Playgroud)

其作用相同:

char str[] = "abcdefghij";
char ch = str['\t'];
Run Code Online (Sandbox Code Playgroud)

为什么它甚至可能?特别是为什么编译器从字符串中挑选第一个char并将其用作下标而不是抛出错误?

Tyl*_*nry 12

首先,所有这些doublefloat东西都是纯误导.逗号运算符的返回值是它的右侧参数,因此(double(), (float(), int()))归结为just int(),尽管它在此过程中创建并丢弃a doublefloat值.所以考虑:

 auto ch = int()["\t\a\r\n\0"]["abcdefghij"];
Run Code Online (Sandbox Code Playgroud)

将评估的第一部分是

 int()["\t\a\r\n\0"]
Run Code Online (Sandbox Code Playgroud)

现在,认识到int()默认构造一个整数,它给它赋值0.所以声明等同于:

 0["\t\a\r\n\0"]
Run Code Online (Sandbox Code Playgroud)

它在C和C++中是一个相当着名的技巧,a[b]并且b[a]是等效的,因为下标运算符被定义为a[b] === *(a + b)并且加法是可交换的.所以这真的是一样的:

 "\t\a\r\n\0"[0]
Run Code Online (Sandbox Code Playgroud)

这当然等于'\t'.现在完整的代码是:

 auto ch = '\t'["abcdefghij"];
Run Code Online (Sandbox Code Playgroud)

出于同样的原因相当于:

 auto ch = "abcdefghij"['\t'];
Run Code Online (Sandbox Code Playgroud)

当然也可以写成

char str[] = "abcdefghij";
char ch = str['\t'];
Run Code Online (Sandbox Code Playgroud)

如果给了"abcdefghij"字符串一个名称,并auto在声明时使用了C++ 0x 关键字ch.

最后,注意\t等于9,因为制表符有ASCII值9,所以str['\t']它是相同的str[9].str由10个字符组成,后跟一个NUL字符终结符(\0),它隐式添加到初始化的字符串文字中.

所以在这两种情况下,最终值ch都是'j'.


ybu*_*ill 8

我会解释为重写:

auto ch = (double(), (float(), int()))["\t\a\r\n\0"]["abcdefghij"];
Run Code Online (Sandbox Code Playgroud)

相当于(只double, float, int用逗号运算符评估所有临时值)

auto ch = (0["\t\a\r\n\0"])["abcdefghij"];
Run Code Online (Sandbox Code Playgroud)

现在标准说:

x[y] == *(x + y)
Run Code Online (Sandbox Code Playgroud)

无论哪一个是指针.所以你得到:

0["\t\a\r\n\0"] == "\t\a\r\n\0"[0] == '\t';
Run Code Online (Sandbox Code Playgroud)