以下两段代码下面会发生什么?
/* Piece #1 : Prints Garbage Values. */
char *res_str(int n) {
return (char [][7]){"Char", "Match", "Jmp", "Split", "None"}[n];
}
/* Piece #2: Prints Correct Values.*/
char *res_str(int n) {
return (char *[]){"Char", "Match", "Jmp", "Split", "None"}[n];
}
__attribute__((packed))
?怎么样?我使用:
来调用函数printf("%s", op_str(n));
答案 0 :(得分:4)
此
(char [][7]){"Char", "Match", "Jmp", "Split", "None"}
在堆栈上创建一个2D数组,并将括号括起来的初始化列表中提供的字符串内容复制到数组的相应插槽中。
此
return (char *[]){"Char", "Match", "Jmp", "Split", "None"}
在堆栈上创建一个char*
s(指向char
的指针)数组,每个数组都指向相应字符串文字的基址。
现在这里有一个问题:当执行超出数组在中声明的块时,数组超出范围。
在您显示的第一个示例中,一旦函数结束,数组将被销毁。这意味着当执行到达printf
时,您不应该读取/写入此内存位置,因为它现在变得无效,您可以篡改。
在第二种情况下,您有一些指向char
的指针指向字符串文字的基址。需要注意的是,字符串文字具有静态持续时间,只要程序就存在。这意味着,当执行返回到printf
时,您仍然可以读取字符串文字,因为它们没有被释放。
请注意,我说" 您仍然可以读取字符串文字"在上面的段落中,但不是写入。这是因为字符串文字是不可变的意味着它们无法更改。 任何改变字符串文字内容的尝试都会导致未定义的行为 。
答案 1 :(得分:2)
与使用变量而不是模糊处理完全相同:
/* Piece #1 : Prints Garbage Values. */
char *res_str(int n) {
char words[][7] = {"Char", "Match", "Jmp", "Split", "None"};
return words[n];
}
/* Piece #2: Prints Correct Values.*/
char *res_str(int n) {
char *words[] = {"Char", "Match", "Jmp", "Split", "None"};
return words[n];
}
第一个返回指向本地数组的第一个元素的指针 - 数组words[n]
衰减到的指针 - 而不是指向存储文字的内存的指针。
由于数组的生命周期在函数返回时结束,因此返回的指针在该点变为无效
使用它是未定义的。
我不知道你的第二个问题是什么意思。
答案 2 :(得分:0)
这是因为子数组超出了范围,函数只返回指针。如果是这样的话,可能会有效:
typedef char array[7];
array res_str1(int n) {
/* The Deobfusscation helps! :) */
char words[][7] __attribute__((packed)) = {"Char", "Match", "Jmp", "Split", "None"};
return words[n];
}
但是C不允许返回数组,因此这段代码甚至不会编译。 '为什么C不允许返回数组'本身可能是一个单独的问题。另外,对于这里,属性(打包)被编译器拒绝(冗余?),但属性(对齐)有效,为什么? 同样,如果数组是静态的,那么这段代码将正常工作。 谢谢大家的答案! :)