c - 返回从 volatile 标量初始化的字符串表现得很奇怪?
问题描述
我试图用字符串文字使逆向工程变得更加困难,比如第一个代码块。我将它初始化为带有挥发物的标量。它是易失的,因此编译器不会对其进行优化并在编译时将其转换为纯字符串文字。
#include <stdio.h>
static const volatile char a = 'a', b = 'b', c = 'c', d = 'd', e = 'e', f = 'f';
inline const char *_GetString(void) {
return (const char[]){a, b, c, d, e, f, 0};
}
const char *GetString(void) {
const char *x = _GetString();
puts(x);
return x;
}
int main(int argc, char *argv[]) {
puts(GetString());
return 0;
}
前面不会打印abcdef
两次。但是,这样做:
#include <stdio.h>
const char *_GetString(void) {
return "abcdef";
}
const char *GetString(void) {
const char *x = _GetString();
puts(x);
return x;
}
int main(int argc, char *argv[]) {
puts(GetString());
return 0;
}
为什么会这样?我怎样才能以这种方式从函数中返回一个字符串,这并不奇怪,但仍然保持函数是内联的并且难以进行逆向工程?
解决方案
复合文字,就像第一个_GetString
代码片段中的内部文字一样,与在同一范围内声明的任何变量具有相同的生命周期。所以当函数返回时,它返回一个指向数组中第一个元素的指针,即一个指向局部变量的指针。这意味着当函数返回时,返回的指针值不再有效,并且尝试使用它会调用未定义的行为。
第二段代码之所以有效,是因为它返回字符串文字的第一个元素的地址,而字符串文字的生命周期是整个程序的生命周期,因此指针仍然有效。